/*useState
一、什么是 useState
useState是React的状态Hook,用于在函数组件里声明、读取和更新本地状态。
基本形态:const [state, setState] = useState(initialValue)
更新有两种:直接赋值 setState(newValue);或基于上一次状态的函数式更新 setState(prev => next)
重要特性:
更新是异步批量的,多次setState会合并在一次渲染中执行
切勿直接修改对象/数组等可变数据,请用不可变更新(拷贝后改)
二、为什么不能直接修改对象/数组等可变数据?
React的更新依据是“引用是否变化”。当调用 setState 时,React会对比新旧引用来决定是否需要触发渲染与更新子组件。
直接修改对象/数组(原地修改)会保留同一个引用,容易导致:不触发重新渲染,UI不更新
三、组件间通信常见方式
父传子(单向数据流):父组件通过 props 传值到子组件
子传父(回调上行):父把回调函数下发到子,子调用回调将数据上行
兄弟组件通信:将共享状态提升到最近共同父组件,再通过父-子流转
全局或跨层级通信:
Context:避免逐层传 props,适用于主题、用户信息、国际化等
状态管理库:Redux、Zustand、Jotai、Recoil 等,适合复杂全局状态
*/
import { useState } from 'react'
function Child({value,handleAdd}) {
return (
<>
<div>我是子组件,我接收到的父亲的参数了:{value}</div>
<button onClick={()=>handleAdd(5)}>点击我加5,调用父亲的方法传5</button>
</>
)
}
const Counter = () => {
const [count,setCount] = useState(0)
const [user, setUser] = useState({name:"tom",tags:["a"]})
//函数式更新
const updateUser = () => {
setUser(prev=>(
{
...prev,
tags:[...prev.tags, "b"]
}
))
setUser(prev=>{
return {
...prev,
name:"Lily",
tags:[...prev.tags,"c"]
}
})
}
function handleAdd(number) {
setCount(c=>c+number)
}
return (
<div>
<button onClick={updateUser}>更新用户</button>
<Child value={count} handleAdd={handleAdd}/>
<p>{user.name}</p>
<p>{user.tags}</p>
</div>
)
}
export default Counter
/*写代码写错了,记录一下问题
四、什么时候setState用函数式更新,什么时候直接赋值?
当“新状态依赖于上一次状态”时:计数累加、数组/对象基于旧值拼接或修改,需要用函数式更新
新状态与上一次状态无关,直接赋值
五、为什么 onClick={() => handleAdd(5)} 而不是 onClick={handleAdd(5)}
onClick 需要的是“函数引用”,点击时再执行。
onClick={handleAdd(5)} 会在渲染阶段立刻调用 handleAdd,并把“返回值”(通常是 undefined)当成事件处理函数,导致:
渲染就触发副作用;
真正点击时没有可调用的函数。
正确写法用一个包装函数,延迟到点击时再调用 handleAdd(5)。等价替代:onClick={handleAdd.bind(null, 5)}
*/
console