redux是属于js的状态管理模式,我们可以借助react-redux连接上redux和react-redux
我们要引起一个组件更新有两种方案
-
修改组建的state数据
-
修改组件的props
所以我们react-redux其实做了这样一件事情
把redux的state映射到组件的props,这样修改redux的state,就会触发组件的props的改变,组件就会更新。这样就只会更新使用到了redux的组件
npm i redux --save
npm i react-redux -S
1.1 创建状态管理器
第一步,我们先创建一个redux状态管理器
import { legacy_createStore as createStore, applyMiddleware } from "redux"function reducer (state = { //初始数据,初始数据作为第一个参数的默认值 msg: "hello", count: 0}, action) { //这里写修改state的行为 //action一定要有type switch (action.type) { case "changeMes": //可以叫其他名字,只不过最好叫payload state.mes = action.payload; //return的值会直接作为state的新值 //一定要再修改完后,返回state //如果配合上react-redux,就必须返回的时候,解除引用 return { ...state } case "addCount": state.count += 1; return { ...state } default: return state; }}let store = createStore( reducer);export default store;
1.2 使用react-redux
第一步,用react-redux提供的Provider组件包裹App
我们用Provider包裹了App,就等于接管了项目
import React from 'react';import ReactDOM from 'react-dom/client';import './index.css';import App from './App';import reportWebVitals from './reportWebVitals';import store from "./store"// 1.js引入provide组件,// 因为我们试图把state映射到props,所以我们要成为所有的组件父组件import { Provider } from 'react-redux';const root = ReactDOM.createRoot(document.getElementById('root'));root.render( <React.StrictMode> {/* 2.用Provider把项目包起来,并且加上一个store属性,给入创建redux对象*/} <Provider store={store}> <App /> </Provider> </React.StrictMode>);//这样子做不好,他会导致整个 项目都刷新。等同于按F5刷新了页面// store.subscribe(() => {// root.render(// <React.StrictMode>// <App />// </React.StrictMode>// );// })// If you want to start measuring performance in your app, pass a function// to log results (for example: reportWebVitals(console.log))// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitalsreportWebVitals();
第二步-使用connect把redux的state映射到组建的props
业务逻辑写到容器组件中
import store from "./store"import { connect } from "react-redux"function ReduxCom (props) { console.log(props); return <div> <div> mes:{props.msg} </div> <div> count: {props.count} </div> <button onClick={() => { props.dispatch({ type: "changeMes", payload: "hello world" }) }}>修改redux的mes</button> <button onClick={() => { props.dispatch({ type: "addCount", payload: "hello world" }) }}>count+1</button> </div>}function mapStateToProps (state) { console.log(state); //state就是redux的state //return的这个对象将会合并到组建的props里 return { mes: state.msg, count: state.count, }}export default connect(mapStateToProps)(ReduxCom);
这样指定的state都映射到props里了
思考:为什么要指定state映射,而不是直接全部映射
因为props的改变会导致组件更新,如果全部映射,那么有的redux中的state数据不是这个组件用的,它的更新也会引起组件更新,所以我们要指定映射组件用到的state,而不是直接全面映射。
第三步,为了让调用更加方便
我们可以把对某个数据的修改写成方法,然后映射到props中,我们可以不映射action,但是为了让调用方便,我们可以映射下
//redux现在和react每有任何关联// redux是属于js的状态管理模式,// 我们可以借助react-redux连接上redux和react-reduximport { connect } from "react-redux"//把redux创建的state全部映射为props-》修改state-》等同于修改了props-》触发了组件更新//哪个组件要使用状态管理//比如我们要再这个组件使用状态管理,我们就在这里引入connectfunction ReduxCom (props){ console.log(props); return ( <div> {props.msg} <button onClick={()=>{{props.changeMsg()}}}>修改redux的msg</button> </div> )}// connect调用后,会返回一个高阶组件,所以我们先调用connect,然后把该组件给到高阶组件// 第一个参数,对于state的映射关系// 必须传递第一个参数,不传第一个,就不会把state映射为props,// 那么修改不会触发更新function mapState (state) { return { msg: state.msg }}//第二个参数function mapAction(dispatch){ return { changeMsg(){ dispatch({ type:'changeMsg', payload:'hello world!' }) } }}export default connect(mapState,mapAction)(ReduxCom)
2.1 redux+react-redux分模块使用
如果项目很大,或者项目划分比较明确,需要将状态管理器也分模块去处理
假设我们有两个模块,我们写成reducer和reducer2
步骤
-
创建不同模块的reducer方法
-
引入combineReducers方法,把不同模块的reducer何在一个对象里给入方法
-
把combineReducers返回的对象给到createStore
//1,引入redux的applyMiddleWareimport { legacy_createStore as createStore ,combineReducers} from "redux";function reducer(state = { // 初始化数据,初始数据作为第一个参数的默认值 msg: 'hello', count: 0}, action) { // 这里写修改state的行为 // action一定要有type switch (action.type) { case 'changeMsg': // 可以叫其他名字,只不过最好叫payload state.msg = action.payload // return的值会直接作为state的新值 // 一定要修改完后,再返回state return { ...state }; case 'addCount': state.count += 1 return { ...state }; default: return { ...state }; }}function reducer2(state = { arr:[]}, action) { switch (action.type) { case 'pushArr': // 对于state里面的数组,对象,我们也得解除引用 let _arr=[...state.arr]; _arr.push(action.payload); return {...state,arr:_arr}; case 'replaceArr': //这里写不了异步操作 state.arr = action.payload; return { ...state }; default: return state ; }}//给入一个对象,对象里面写入我们的模块//然后得到一个合并的reducerlet combineReducer=combineReducers({reducer,reducer2})let store=createStore(combineReducer)export default store
然后我们state就会分开模块,**注意使用的时候要拿出具体模块**
import store from "./store"import { connect } from "react-redux"function ReduxCom (props) { console.log(props); return <div> <div> mes:{props.msg} </div> <div> count: {props.count} </div> <button onClick={() => { props.changeMes() }}>修改redux的mes</button> <button onClick={() => { props.addCount(); }}>count+1</button> </div>}function mapStateToProps (state) { console.log(state); return { //因为分了模块,所以取出得先取处模块,再取模块得数据 mes: state.reducer.msg, count: state.reducer.count, arr: state.reducer2.arr }}function mapActions (dispatch) { return { changeMes () { dispatch({ type: "changeMes", payload: "hello world" }) }, addCount () { dispatch({ type: "addCount" }) } }}export default connect(mapStateToProps, mapActions)(ReduxCom);
我们可以看到我们从state取数据都是先取出reducer或者reducer2模块,再取数据