目录
在类组件中使用redux
1.首先安装:
npm install redux
2.创建reducer
3.在文件中创建store,将reducer传入createStore中:
4.类组件中通过getState()读取数据:
5.组件中通过定义action,派发action改变state中的数据:
6.接着回到reducer中,处理组件派发过来的action,并更新改变state中的数据:
7.最后一步,通过store.subscribe“发送订阅信息”,即实时更新组件中的数据:
但是以上代码需要改进,第5步中的action不应该直接放在组件中,而是应该将action定义在单独的文件中,方便后期的维护,同时借助TypeScript的类型检验来减少容易写错代码的风险,以及第6步中switch中的case参数不应该直接写字符串,应该也将其定义到单独的action文件中,供多个地方使用该action.type
改进:
在redux目录下创建一个language,将于language业务有关的目录全部迁移进去,并创建languageAction文件,在这统一定义相关的action
languageAction文件:
在第6步中,将languageAction中定义的联合类型LanguageTypes传到函数的参数action中,从而享受TypeScript的类型检验
最后修改组件中第5步中的派发action方式,通过 languageAction.ts统一定义的actionCreator方法来定义action:
完成改进
第二种写法,在类组件中使用react-redux改造
1.安装
npm install react-redux
如果要支持Typescript,还需安装:
npm install @types/react-redux --save-dev
在index.tsx中,用Provider将整个应用包裹起来
2.子组件中,引入相关:
3.在store.ts中定义所有state的类型:
4.回到子组件中,定义mapStateToProps和mapDispatchToProps
并将导出的组件包裹起来,把定义的mapStateToProps和mapDispatchToProps作为参数传入:
5.在组件中使用:
可以看出在类组件中使用React-redux十分繁琐,因此推荐第三种写法
第三种写法,在函数式组件中使用React-redux
1.在组件中获得全局store的数据,需要先引入useSelector:
但如果想要完美兼容Typescript,需要对useSelector进行以下封装:
其中rootState是在store.ts中定义的联合类型:
接着在组件中通过useSelector获取全局定义中的language和languageList两个数据
2.dispatch派发action
引入useDispatch:
结合redux-thunk
首先安装:
npm install redux-thunk
为什么要redux-thunk?
下面是homePage中的一段代码,我们把请求api的方法直接放在组件的componentDidMount中,
但这时我们更希望将这段方法抽离成全局的方法,这样就不仅能服务于homePage这个页面,其它页面也可以使用,因此我们需要将这段方法与redux建立联系
再回来看redux的文件目录
除了定义文件hook.ts和store.ts,redux中的核心业务文件只有Action文件和Reducer文件,但ActionCreator只是提供定义action的方法,而Reducer文件中不允许有携带副作用的函数存在,因此目前来讲我们不能将请求api的方法放置在这里的任何一个文件中,这时就需要请求外援大名鼎鼎的redux-thunk了
在store.ts中引入redux-thunk和 applyMiddleware
在creatStore中使用:
然后也要在action文件中定义相关的actionCreator:
引入:ThunkAction
定义actionCreator
注意ThunkFunction泛型中接收四个参数分别是
1.函数的返回类型,这里没有返回,所以为void
2.state的类型
3.额外参数的类型,unKnow
4.action的类型,如果不加入RecommendProductAction类型,创建的giveMeDataActionCreator中将无法调用那三个dispatch(fetchRecommendProductxxxxxxxActionCreator( ))
最后,在homePage中使用,引入刚刚定义的giveMeDataActionCreator
改造类组件中的mapDispatchToProps
改造componentDidmount
在redux中使用中间件
为什么需要中间件?假设现在有一个需求,需要在每次dispatch actions时同时打印当前state,action以及更新后的state,这时,中间件允许我们在发送action时截取这个action,并且在这个过程中添加一些附加的操作,相当于对其进行了封装
首先记住中间件格式
在redux文件夹下创建文件夹middlewares
在actionLog.ts定义该中间件:
在store.ts中,将该actionLog中间件作为参数,传入到createStore的第二个参数,applyMiddleWare中
redux-toolkit优化改造
有没有发现每个actionCreator文件中都存在大量的冗余代码,模板代码。
比如:每个actionCreator中都需要定义action的type
每个actionCreator中都需要定义action
每个reducer中都需要通过switch来写代码
redux-toolkit就是用来解决这样的问题
安装:
npm install @reduxjs/toolkit
创建slice.ts
编写slice.ts
改造store.ts
将combineReducers改成从@reduxjs/toolkit中引入,而不再从redux中引入
改为:
然后将ProductDetailSlice.reducer作为参数传入combineReducers中,记住一定是.reducer的形式
在组件中使用:
引入productDetailSlice:
通过productDetailSlice.actions.xxxx的方式来调用reducer
若需要在slice.ts文件中处理异步函数:
1.引入configureStore,
2.在store.ts中将原来的用createStore创建的store注释掉
改成使用configureStore来创建store(这里的actionLog是之前创建的中间件)
3.使用createAsyncThunk来创建异步函数
引入:
定义异步函数getProductDetail
4.将ProductDetailSlice中原来的 reducers改成extraReducers,并修改它们的名字
原来的ProductDetailSlice:
修改后的ProductDetailSlice:
完成
使用redux-persist将redux存储持久化
redux-persist可以像localStorage或cookie的方式将redux中的数据存储起来
安装
npm install redux-peisist
在store.ts中引入persistStore,persistReducer和storage
定义配置选项persistConfig
第二个参数storage实际上就是localStorage,而whiteList是白名单,代表只存储白名单里的数据,这里只存储user这个reducer
同时,也有黑名单blackList,与whiteList相反,除了列表中的reducer,其它所有的reducer都将会被储存
然后用引入的persistReducer来定义新的persistedReducer,将刚刚定义的配置选项persistConfig和rootReducer作为参数传入 :
然后,将
configureStore中的reducer替换成刚刚定义的新persistedReducer
将
改成
使用一开始引入的persistStore,将新的store作为参数传入,得到persistor:
最后修改导出的store
原来的导出方式:
改成:
将persistor一同导出
如何使用:
在index,ts中导入上边导出的store和persistor联合体
以及引入PersistGate
然后将rootStore.store作为全局参数传入Provider的store中
将刚刚引入的PersistGate将<App />包裹起来,并将rootStore中的persistor作为参数传入.
注意,PersistGate除了接收persistor参数,还可以接收一个"loading",可用来定义加载持久化store时的加载界面,若写成<PersistGate loading={ null }></PersistGate>,则在加载时界面直接显示空白