定義:redux 是React技術(shù)棧使用最為廣泛的狀態(tài)管理奶赠。一款個人作用,基于 Flux數(shù)據(jù)架構(gòu)思想的開源工具。
牢記三個三
1故源、第一個“三”(3個api):createStore紊遵、combineReducers账千、applyMiddleware
2、第二個“三”(3個特點(diǎn)):單一數(shù)據(jù)源暗膜、store是只讀的匀奏、使用reducer純函數(shù)來修改store。
3学搜、第三個“三”(3個概念):State娃善、Action论衍、Reducer。
store
store.getState() 用于獲取store中所有的state
store.subscribe() 用于添加一個change事件聚磺,監(jiān)聽store變化
store.dispatch() 用于派發(fā)一個action
redux集成
1坯台、環(huán)境配置
cnpm i redux -S
cnpm i react-redux -S
cnpm i redux-thunk -S
第一步,構(gòu)建store的邏輯
const store = createStore(
combineReducers({good,user,...}),
compose( applyMiddleware(ReduxThunk),
applyMiddleware(ReduxLogger),
...
) )
import produce from 'immer'
function reducer(state=initState, action) {
return produce(state, newState=>{
switch(action.type) { case '': }
})
}
export default reducer
第二步,連接redux和react
function App() {
return (
<Provider store={store}> </Provider>
)
}
第三步,在react組件中使用store
1、如果是類組件, 只能使用 connect() 高階組件
@connect(
state=>({msg:state.user.msg, ....}),
dispatch=>({changeMsg:(payload)=>dispatch({type,payload})}) )
class Home extends PureComponent {
}
export default Home
class Home extends PureComponent {?
}
export default connect(
state=>({msg:state.user.msg, ....}),
dispatch=>({changeMsg:(payload)=>dispatch({type,payload})})
)(Home)
2瘫寝、如果是函數(shù)式組件, 使用 connect() 高階組件
export default connect(
state=>({msg:state.user.msg, ....}),
dispatch=>({changeMsg:(payload)=>dispatch({type,payload})})
)(props=>(<div></div>))
3蜒蕾、如果是函數(shù)式組件(react v16.8),還可以使用react-redux的hooks寫法
export default () => {
? const msg = useSelector(state=>state.user.msg)
? const dispatch = useDispatch()
}
重新梳理redux中的三個概念
store, 如何創(chuàng)建store, store有哪三個特點(diǎn)(單一數(shù)據(jù)源,只讀的,只能使用reducer來修改store)
action, 是一個plain object, 它是固定格式的{type:'信號',payload:'負(fù)載'},你可以把它理解成是"一封郵件", action是給dispatch(action)用的,這表示的是"一個業(yè)務(wù)邏輯".
從redux架構(gòu)的角度,思考下面幾個問題?
1、為什么要把redux架構(gòu)中的所有type抽離成常量,并且放在同一個type文件中?
就是為了低耦合,避免協(xié)同開發(fā)中對type賦值沖突的問題(如果type沖突,"信號"就沖突了,那么redux工作中肯定出現(xiàn)bug,這也違背了"單向數(shù)據(jù)流"的設(shè)計理念).
2矢沿、redux默認(rèn)不支持異步調(diào)接口, redux的store如果接收到了一個非action={type,payload}的信號時,會報錯. 那該怎么辦呢?
使用redux-thunk來解決問題. redux-thunk這個中間件作用是在store收到信號時對"信號"的數(shù)據(jù)類型進(jìn)行判斷,如果function類型,redux-thunk就調(diào)用這個funciton并把dispatch傳遞這個function,還會攔截掉這個function, 所以這個function就不會抵達(dá)reducer.
3滥搭、為什么要封裝"action生成器"?
其一是為了把業(yè)務(wù)邏輯(調(diào)接口的邏輯)從react組件中抽離出來,?
其二是action可以被復(fù)用.(在這里,你可把"action生成器"理解成一個具體的業(yè)務(wù)邏輯).
redux原理? redux和mobx有什么區(qū)別?分別有什么優(yōu)勢和劣勢?
redux是基于事件監(jiān)聽,react上下文,高階組件來實(shí)現(xiàn)的, 比較適用中大型項目.
mobx是典型的響應(yīng)式的狀態(tài)管理工具, 比較適用于中小型項目.
擴(kuò)展
一、如何封裝connect()?
首先要理解connect到底在做什么? mapStateToProps把store.getState()中的數(shù)據(jù)添加到當(dāng)前UI組件的props上, mapDispatchToProps給當(dāng)前UI組件的props方法注入store.dipatch這個API, connect()還做了另一件重要的事,在當(dāng)前UI組件中監(jiān)聽store變化.
思路1: 編寫類組件,使用 contextType接收ReactReduxContext上下文(也就是說你在當(dāng)前UI組件中就拿到了store數(shù)據(jù)), 在componentDidMount()監(jiān)聽store的變化,當(dāng)store變化時強(qiáng)制更新頁面.
思路2: 編寫函數(shù)式組件, 使用useContext()拿到上下文(就是拿到了store數(shù)據(jù)),在useEffect()監(jiān)聽store變化,當(dāng)store變化時set*方法觸發(fā)當(dāng)前組件更新.
二捣鲸、如何封裝useSelector()?
它所做的事情和connect()是一樣的. 使用useState/useReducer都能實(shí)現(xiàn).