前言
react hooks 是 React 16.8 的新增特性。 它可以让我们在函数组件中使用 state 、生命周期以及其他 react特性,而不仅限于 class 组件。react hooks 的出现,标示着 react中不会在存在无状态组件了,只有类组件和函数组件。具体可查看官网。
优势:
- 函数组件不能使用state,遇到交互更改状态等复杂逻辑时不能更好地支持,hooks让函数组件更靠近class组件,拥抱函数式编程。
- 解决副作⽤问题,hooks出现可以处理数据获取、订阅、定时执行任务、手动修改 ReactDOM这些⾏为副作用,进行副作用逻辑。比如useEffect。
- 更好写出有状态的逻辑重用组件。
- 让复杂逻辑简单化,比如状态管理:useReducer、useContext。
- 函数式组件比class组件简洁,开发的体验更好,效率更⾼,性能更好。
- 更容易发现无用的状态和函数。
useState介绍
const [state, setState] = useState(initialState);
返回一个 state,以及更新 state 的函数setState。
- state是要设置的状态 。
- setState是更新state的方法。setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列。
- initState是初始的state,可以是随意的数据类型,也可以是回调函数,但是函数必须是有返回值(惰性state)。
惰性初始 state initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略。如果初始 state需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用:
const [state, setState] = useState(() => { const initialState = someExpensiveComputation(props); return initialState; }); ```
在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同。
setState(newState);
在后续的重新渲染中,useState 返回的第一个值将始终是更新后最新的 state。
useState原理
我们需要写一个 useState 方法,会返回当前状态和设置状态的方法,每当状态改变之后,方法中会调用刷新视图的 render 方法。状态我们需要放在最外面,方便下次执行函数时可以重新取值。初始状态只会在函数第一次执行的时候赋值。
let memoizedState;
function useState (initialState) {
memoizedState = memoizedState || initialState
function setState (newState) {
memoizedState = newState
render()
}
return [memoizedState, setState]
}
这样确实是可以正常使用,但是当多个 useState 存在的时候就有问题了,只能变一个状态了。现在我们需要优化我们的 Hooks ,解决多个 useState 同时使用的问题,当多个状态存在的时候,我们需要使用数组保存状态。
let memoizedStates = []
let index = 0
function useState (initialState) {
memoizedStates[index] = memoizedStates[index] || initialState
let currentIndex = index
function setState (newState) {
memoizedStates[currentIndex] = newState
render()
}
return [memoizedStates[index++], setState]
}
useState使用
例子:
function App () {
const [ count, setCount ] = useState(0)
return (
<div>
点击次数: { count }
<button onClick={() => { setCount(count + 1)}}>点我</button>
</div>
)
}
相同值,当我们在使用 useState 时,修改值时传入同样的值,我们的组件是不会渲染的。
function App () {
const [ count, setCount ] = useState(0)
console.log('我就看你渲染不')
return (
<div>
点击次数: { count }
<button onClick={() => { setCount(count)}}>点我</button>
</div>
)
}