// 如何在项目中集成redux(真实开发中,需要网络请求数据的集成)
// 1.首先是安装相关的依赖 // yarn add redux(首先是安装redux) // yarn add react-redux(再其次是安装react-redux,其作用是能够使redux和组件关联起来) // yarn add redux-thunk(中间件,通过其进行网络请求)
// 2.在项目的src文件夹下面创建store文件(这个文件就是redux的文件夹)-->创建reducer.js文件以及index.js文件
// reducer.js文件: //导出对项目中的多个reducer进行合并的函数(为什么是redux-immutable呢?主要是进行性能优化的作用) // 所以需要安装:yarn add redux-immutable import { combineReducers } from 'redux-immutable' // 导入项目中的多个reducer:(这里因为每个路由中的reducer都是以reducer命名的,所以需要在导入时对reducer进行重新的命名,避免多个reducer重名的问题),这里的reducer会是多个,但是这里只使用一个reducer进行举例说明罢了 import { reducer as recommendReducer } from '../pages/diccover/c-pages/recommend/store'; //这里就是合成的reducer,需要传入的是一个对象 const cReducer = combineReducers({ recommend:recommendReducer, }) // 导出合成的reducer,并在index.js文件中使用 export default cReducer
// index.js文件:(创建store) // 在redux中导入需要创建store的函数,以及导出需要使用中间件的函数 import { createStore,applyMiddleware,compose } from 'redux' // 导入redux-thunk中的中间件 import thunk from 'redux-thunk' // 导入在reducer.js文件中带出的合成的reducer import reducer from './reducer' // 使用那个浏览器的调试工具需要引入的一段代码 const composeEnhancers = window.REDUX_DEVTOOLS_EXTENSION_COMPOSE || compose //通过createStore创建store对象 // 两个参数: // 1.reducer【项目中一般有多个reducer,多数是一个路由下面是有一个reducer,所以需要对reducer进行拆分】--> 因为需要多个reducer,所以需要创建一个reducer.js的文件,来对项目中的多个reducer进行合并 // 2.对store进行加强的一些方法,此处传入的是一个中间件,以及使用浏览器中的redux的那个调试工具 const store = createStore(reducer,composeEnhancers(applyMiddleware(thunk))) // 导出创建的store,以供全局使用 export default store
// 3.在App.js文件中(这里只是一些redux需要的一些引入) // 在react-redux中带入provider import { Provider } from 'react-redux' // 导入创建的store import store from './store'
export default memo(function App() { return ( //使用Provider将store中存放的数据共享出去,注意:这里的是store而不是value //还有一个点就是在项目中Provider组件是放在最顶层的,在一层是路由相关的组件,后面才是自己定义的一些组件 ... ) })
//4.在每个路由文件下下面创建一个store文件夹(创建index.js\reducer.js\constants.js\actionCreators.js文件) // reducer.js文件:定义单个路由自己的reducer import { Map } from 'immutable' // 导入定义的数据修改的action的常量(这里有两种导入的方式) // 导入方式一: // import { CHANGE_TOP_BANNERS } from './constants'; // 导入方式二:(这一种导入的方式是直接全部导入,在使用的时候就需要:actionTypes.CHANGE_TOP_BANNERS) import * as actionTypes from './constants' // 定义默认的state(比如这里开始是轮播图的数据,所以可以定义一个空的数组) const defaultState = Map({ topBanners:[], }) // 定义单独的reducer函数(并且有两个参数:第一个参数是state,一般都是保证state=defaultState;第二个参数是action,就是修改state中的数据需要派发的action) function reducer(state = defaultState, action){ switch(action.type){ case actionTypes.CHANGE_TOP_BANNERS: // return {...state, topBanners: action.topBanners} return state.set("topBanners",action.topBanners) // 这里必须使用default来结尾reducer,不然就会报错 default: return state } } // 导出reducer export default reducer
// 5.定义自己的reducer中需要使用的常量文件(防止我们拼写出错) export const CHANGE_TOP_BANNERS = "recommend/CHANGE_TOP_BANNERS"
// 6.创建index.js文件 // 导入创建的reducer文件 import reducer from './reducer' // 并将创建好的reducer文件导出 export { reducer }
// 7.创建actionCreators.js文件(这个文件中主要有发送网络请求的中间件以及dispatch一个函数,来进行网络的请求) // 首先是导入创建的常量 import * as actionTypes from './constants' // 导入发送网络请求中导出的那个函数 import { getTopBanners } from '@/services/recommend' // 定义在reducer中的action(并且在下面也一起派发出去) const changeTopBannerAction = (res) => ({ type:actionTypes.CHANGE_TOP_BANNERS, topBanners:res.banners }) // redux-thunk中定义的action函数 export const getTopBannerAction = () => { return dispatch => { // 这里面就是发送网络请求的action getTopBanners().then(res => { // 这里是:dispatch(函数)来发送网络请求 dispatch(changeTopBannerAction(res)) }) } }
// 8.针对每一个模块单独建一个发送网络请求的文件在services文件夹中(比如recommend.js文件) // 首先是导入自己项目中对于axios的封装 import request from './request' // 导出自己关于banners网络请求的代码(如果网络请求需要参数就在括号里面写上队形的参数) export function getTopBanners(){ return request({ url:"/banner" }) }
// 9.使用hooks让组件和redux关联(组件和redux关联主要做的有两件事情:1.获取数据、2.操作数据dispatch) import React, { memo,useEffect } from 'react' import { useSelector,useDispatch,shallowEqual } from 'react-redux'
import { getTopBannerAction } from '../../store/actionCreators' function JHRecommend(props) {
// 拿到recommend中的数据 const { topBanners } = useSelector(state => ({ topBanners:state.recommend.topBanners }),shallowEqual)
//直接拿到dispatch对象 const dispatch = useDispatch()
// 发送网络请求(第二个参数写依赖什么,当改依赖发生改变的时候组件就会重新渲染) useEffect(() => { dispatch(getTopBannerAction()) },[dispatch])
return (
{topBanners.length}
export default memo(JHRecommend)