1.useState
(1)useState可以在react中进行简单的状态管理。
import React, { useState } from "react";
function Counter() {
// 进行状态初始化
const [count, setCount] = useState(0);
return (
<div className="App">
count:{count}
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
export default Counter
可以方便的使用定义好的setCount方法更新count的值。
(2)使用对象
如果遇到该组件中state数量比较大的时候,可能会出现下面这种情况:
example:
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const [count3, setCount3] = useState(0);
const [count4, setCount4] = useState(0);
const [count5, setCount5] = useState(0);
……
这个时候就觉得一条条的useState写起来十分繁琐,此时可以选择类似component组件this.state写法,将一些状态集中放在一个对象中,通过setCounts({...counts,……})的方式来更新状态。
const [counts,setCounts]=useState({
count1:0,
count2:0,
count3:0,
count4:0,
count5:0
……
})
……
<div className="App">
<p>count:{count}</p>
<p>count1:{counts.count1}</p>
<p>count2:{counts.count2}</p>
<p>count3:{counts.count3}</p>
<p>count4:{counts.count4}</p>
<p>count5:{counts.count5}</p>
……
<button onClick={
() => setCounts({...counts,count1:counts.count1+1})
}>+1</button>
</div>
使用useState会发现状态更新的逻辑比较零散,分布在UI各处,且不便于测试。
2.useReducer
useReducer可以解决上面useState无法解决的问题。
官方链接
useRducer是useState的替代方案。它接收一个形如(state, action) => newState的reducer以及初始化对象,并返回当前的state以及配套的dispatch方法。
某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数 。
const [state, dispatch] = useReducer(reducer, initialArg, init);
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
计数器代码经过useReducer改造后,乍一看代码反而更长了。但是如果在state 逻辑较复杂的场景下,效果就会体现出来:
- 用useReducer将state集中在一起,会使state的逻辑更加有条理,我们能够清楚的了解到state的变化,可读性更好。
- useReducer的逻辑脱离了UI,可以独立复用。
- reducer是一个js方法,与UI无关,使我们更容易的进行自动化测试,也可以在chrome中进行调试。
但是useReducer的局限也很明显:useReducer虽然很好的分离了逻辑和UI,但是无法进行跨组件的状态共享。
3.useReducer和useContext使用
useContext可以对它所包裹的组件树提供全局共享数据。
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定
const value = useContext(MyContext);
import React,{useReducer,useContext} from 'react';
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
// 定义context
const Ctx=React.createContext(null);
const Parent=()=>{
const [count,dispatch]=useReducer(reducer,initialState);
return (
// 在这里向子组件传递ctx
<Ctx.Provider value={[count,dispatch]}>
<div>
parent:{count}
<Child />
</div>
</Ctx.Provider>
)
}
const Child=()=>{
//在这里使用context
const [count,dispatch]=useContext(Ctx);
return (
<div>
child:count:{count}
<button onClick={()=>dispatch({type:'increment'})}>+1</button>
<button onClick={()=>dispatch({type:'decrement'})}>-1</button>
</div>
)
}
export default function App(){
return <Parent />
}
如果我们的组件层级较深,且涉及父子组件传值,可以考虑这种方式。
其中可能涉及到性能优化,可以使用useCallback来减少不必要的渲染。
4.useSelector、useDispatch配合redux进行状态共享
通常在react组件中使用redux,需要用provider、connect包裹react组件,还有mapState、mapDispatch 等固定的代码,才能使用store中的state和action。
react-redux在7.1之后,可以使用useSelector、useDispatch等HooksApi替代connect,可以减少模板代码。
(1)创建并引入redux的store
import { createStore } from 'redux'; // redux
import { Provider } from 'react-redux';
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
const stores = createStores(reducer,initialState );
function App() {
return (
<Provider store={stores}>
<Router />
</Provider>
);
}
export default App;
(2)useSelector
可以访问到store中的各种状态
const count=useSelector(state=>state.count)
(3) useDispatch
可以获取到dispatch
const dispatch=useDispatch();
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
function Counter() {
const count=useSelector(state=>state.count)
const dispatch = useDispatch()
return (
<div>
<p>count:{count}</p>
<button onClick={()=>dispatch({type:'increment'})}>+1</button>
</div>
);
}
export default Counter;
5.其他方法
除了Redux之外,现在还有很多适用于hook的状态管理工具:hox、stamen、icestore……