什么时候用到 Redux ?
有人曾说过 : “如果你不知道是否需要 Redux,那就是不需要它 “
接着又有人补充 : “只有遇到 React 实在解决不了的问题,你才需要 Redux 。”
Redux的流程
Redux 的三个3原则
1️⃣ 三个api: createStore() / combineReducers() / applyMiddleware()
2️⃣ 三个特点: store是只读的 / 单向数据流 / 修改store只能通过纯函数reducer来修改
3️⃣ 三个概念: store / reducer / action
Redux 的基本概念和API
1. Store 就是保存数据的地方,可以把它看成是一个容器,整个应用只能有一个store
Redux提供 createStore() 这个函数,用来生成store()
1 | import { createStore } from 'redux' |
2. State,如果把Store看成是一个仓库,那么State 就是仓库的中货物, 每个货物对应一个State;
在Redux中,Store 对象包含着所有的数据,如果想要拿到期中的数据,就要对Store生成快照,此时生成的数据就叫State
Redux规定,一个State对应一个View,只要State相同,View就相同
3. Action
State的变化,会导致页面 即View的变化,但是用户接触不到State,只能接触到View;所以State 的变化必须是View 导致; 而Action就是 View 发出的通过,表示State 应该要发生变化了
Action 是一个对象 ,其中type是必填属性
1 | const payload={ |
4. dispatch()
dispath()是View发出Action的唯一方法,当用户在 View 触发 dispatch, dispatch会生成一个Action()方法, 将它发送给Store
使用dispatch的方式有很多,可以使用高阶组件或hooks
1 | //使用hooks |
5. Reducer
Store 收到Action 后,必须给出一个新的State,这样View才会发生变化,这种State的计算过程就叫Reducer;
也就是说必须根据 View 的变化 修改Store,而Store是只读,只能使用纯函数,即只能在Reducer中修改–> 得出 Reducer 是一个纯函数
纯函数表示:只要是同样的输入,必定得到同样的输出。
🥖 Reducer 函数接收两个参数,一个是初始State,另一个是action
1 | function reducer(initState={},ation){ |
在组件中使用 Redux
使用上下文Provider 将store传到App中
在组件中,可以使用高阶组件或hooks将react和redux连接起来
- 使用高阶组件
1 | //引入 |
1 | function mapStateToProps(store){ |
fn2 是 mapDispatchToProps 将View 中修改的数据 dispatch 到reducer 的action中 ,action通过dispatch中的数据修改state
1 | function mapDispatchToProps(dispatch){ |
- 使用hook
1 | import { useSelector,useDispath } from 'react-redux' |
Redux 中调接口
redux只支持 dispatch 同步的action,并且要求action只能使用plain object
当react组件中dispatch(fetch)触发调接口,此时fetch并不是一个plain object,是一个函数,redux的store收到一个plain object的action时就会报错
所以异步的action需要使用一个第三方库 redux-thunk
creactStore 使用一个中间件, thunk
creactStore(reducer,applyMiddleware(thunk))
🦴 完成一次异步的action,需要两次派发
🦴 第一次派发一个空的action,
🦴 第二次才将action派发到store中
🟣 此时,第一次dispatch的action会被thunk这个中间件接收,thunk中首先会判断,此时这个action是不是一个函数,如果不是,原封不动的将这个action转发store中; 如果 此是这个action是一个函数,那么thunk会执行函数内部的代码,执行第二次派发,直接执行调接口这个异步操作,执行完毕再将结果转发到store中
1 | const getMusic = (payload){ |
分模块
- 使用 combineReducers()函数进行模块划分,接收一个对象,存放的是每个子reducers,使用是需加上每个模块名,即命名空间
1 | import todo from './todo' |
action生成器
action.type