本文已参加「新人创作礼」活动,一起开启掘金创作之路。
Hook使用规则
- 只能在函数的最外层调用Hook,不能在循环、条件判断或子函数中调用。
- 只能在React函数组件或自定义Hook中调用Hook,不可在其他JavaScript函数中使用。
useState基本用法
const [state,setState] = useState<type>(initialState)
参数
参数类型type
useState右侧的<>部分是typeScript中泛型的用法,用来约束参数initialState的类型。
参数初始值initialState
- initialState参数可以是具体的值,也可以是函数返回的值。
- initialState参数只在初始渲染中起作用,后续渲染时会被忽略。
返回值
- useState的返回值是一个数组,数组第一个元素是state,第二个元素是用来更新state的函数。
- state和setState变量名可以按需求改变。例如某组件是一个计数器,计时器中保存的state是当前计数的值,那么变量名可以设为counter;而函数名约定为set+变量名(小驼峰)setCounter。
setState
- setState函数的参数可以是值或更新函数。
- 如果需要根据原来的state更新state,建议用函数更新!!!如count计时器值+1:
setCount(preCount => preCount +1),React保证更新函数的参数始终是最新的state。若用值更新可能会出现异常,如setCount(count+1),因为在异步架构下React不保证执行setCount时拿到的count是最新的。 - setState函数是稳定的,它不会在组件重新渲染时发生变化。所以不需要在useEffect或useCallback等Hook的依赖列表中添加setState。
- setState函数不会自动合并更新对象,但可以使用展开运算符来达到合并更新对象的效果。如:
setState(preState =>{...preState,...updState})
函数更新与值更新的优劣对比
- 如果需要原来的state值才能做更新,建议用函数更新。函数更新的优点是可以保证能拿到最新的state;缺点是react不对函数式更新做异步、批量更新优化。
- 如果不需要原来的state就能做更新,建议用值更新。值更新的优点是react会对值更新做异步、批量更新优化;缺点是在值更新时去取state可能不是最新的。
在一个组件中使用多个state变量
- 函数组件中可以同时使用多个useState,React依靠Hook调用的顺序识别并使用多个state。
- React会在单次渲染过程中更新所有待更新的state变量。
- React官方建议将state切分成多个state变量。
集中式state案例
import React, { memo, useState } from "react"
type Style = {
color: string,
background: string
}
const Show: React.FC<{ state: Style }> = (props) => {
const { color, background } = props.state
console.log("Show")
return (
<div style={{color,background}}>
测试文字,文字的颜色和背景色可以切换!
</div>
)
}
const HandleColor: React.FC<{
setState: React.Dispatch<React.SetStateAction<Style>>
}> = memo((props) => {
const { setState } = props
console.log("HandleColor")
return (
<button onClick={() => setState((preState => preState.color === "red" ? { ...preState, color: "blue" }:{ ...preState, color: "red" }))}>点我改变颜色</button>
)
})
const HandleBackground: React.FC<{
setState: React.Dispatch<React.SetStateAction<Style>>
}> = memo((props) => {
const { setState } = props
console.log("HandleBackground")
return (
<button onClick={() => setState((preState => preState.background === "black" ? { ...preState, background: "gray" } : { ...preState, background: "black" }))}>点我改变背景</button>
)
})
const App = () => {
const [state, setState] = useState<Style>({ color: "red",background:"black" })
console.log("渲染了App")
return (
<>
<Show state={state}/>
<HandleColor setState={setState}/>
<HandleBackground setState={setState} />
</>
)
}
export default App
点击“在线案例”可以在线看代码的表现。
分散式state案例
import React, { memo, useState } from "react"
const Show: React.FC<{
color: string,
background: string
}> = (props) => {
const { color, background } = props
console.log("Show")
return (
<div style={{color,background}}>
测试文字,文字的颜色和背景色可以切换!
</div>
)
}
const HandleColor: React.FC<{
setColor: React.Dispatch<React.SetStateAction<string>>
}> = memo((props) => {
const { setColor } = props
console.log("HandleColor")
return (
<button onClick={()=>setColor((preState=>preState==="red"?"blue":"red"))}>点我改变颜色</button>
)
})
const HandleBackground: React.FC<{
setBackground: React.Dispatch<React.SetStateAction<string>>
}> = memo((props) => {
const { setBackground } = props
console.log("HandleBackground")
return (
<button onClick={()=>setBackground((preState=>preState==="black"?"gray":"black"))}>点我改变背景</button>
)
})
const App = () => {
const [color,setColor]= useState<string>("red")
const [background, setBackground] = useState<string>("black")
console.log("渲染了App")
return (
<>
<Show color={color} background={background} />
<HandleColor setColor={setColor}/>
<HandleBackground setBackground={ setBackground}/>
</>
)
}
export default App
点击“在线案例”可以在线看代码的表现。
对比分析
通过集中式state和分散式state代码对比可以看到分散式state代码更易于做组件拆分,可读性和可维护性更好。