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……