一、redux是什么?
redux 就是react 全局状态管理,作用是存放全局数据
二、核心
state:存放数据
reducer:修改仓库数据
是一个函数,参数一:仓库中的数据,参数2:行为 actions
返回值就是 最新的仓库数据
就是在reduce中定义的方法,修改数据,相当于mutations
只能是同步方法
actions:派发行为触发reducer; 语法:sotre.dispatch({type:'add'})
语法:
function reducer( state={age:10,name:'lisa' },actions){ switch(action.type){ case "add": return {...state, age:state.age+1 }; case "reduce": return { age:state.age-1 } default: return state } }
三、使用redux
1、安装React-redux
# NPM
npm install redux
# Yarn
yarn add redux
2、在src目录下创建store文件夹,index.js文件
在项目中使用到哪些api
createStore
作用:创建仓库
语法:let store=createStore(reducer,中间件);
输出store:
@@observable: ƒ observable() 观察仓库中的数据、
dispatch: ƒ dispatch(action) 触发reducer、
getState: ƒ getState()获取到仓库中的数据、
replaceReducer: ƒ replaceReducer(nextReducer) 替换reducer、
subscribe: ƒ subscribe(listener) 订阅
//创建仓库 import {createStore} from 'redux' // createStore=>创建仓库 //语法 //let store = createStore(reducer,中间件) // reducer => 自己定义 // 1他是一个函数 // 2参数1 仓库中的数据 参数2 行为 actions // 3这个reduer 返回值 就是最新的仓库中的数据 // 4redcuer =》就是在reducer中定义方法修改数据 =》vuex mutations function reducer(state={age:10},actions){ switch(actions.type){ case "add": console.log('add',state); return {age:state.age+1}; default : return state } } let store = createStore(reducer) /** * * @@observable: ƒ observable() 观察仓库中的数据 dispatch: ƒ dispatch(action) =》触发reducer getState: ƒ getState() =>获取到仓库中的数据 replaceReducer: ƒ replaceReducer(nextReducer) 替换reducer subscribe: ƒ subscribe(listener) 订阅 * * * * **/ export default store
3、在App.js根组件中使用仓库
在组件中使用仓库
引入仓库 import store from './store/index'
获取仓库中的数据:store.getState().meReducer.age; (meReducer.age指的是meReducer中的age属性)
触发reducer:store.dispatch({type:"add"})
import logo from './logo.svg'; import './App.css'; // 在组件中引入仓库 import store from './store/index' import {useState} from 'react' function App() { // 1获取到仓库中的数据 // console.log(store.getState()); // let age = store.getState().age let [age,setAge] = useState(store.getState().age) const changeAge = ()=>{ //触发 reducer store.dispatch({type:'add'}) // 问题=》仓库中的数据更新了=》但是视图没有更新 =》组件没有更新 // 1 讲这个数据=》动态数据 // setAge(仓库中的最新数据) =>和仓库进行关联 setAge(store.getState().age) } return ( <div className="App"> <h2>我的年龄{age}</h2> <button onClick={()=>changeAge()}>修改仓库选中数据</button> </div> ); } export default App;
四、combineReducers 合并reducer
combineReducers:
作用:合并reducer
语法:let reducers = combineReducers({属性:各自的reducer, 属性:各自的reducer})
使用webpack中的api:require.context 自动获取到文件中的暴露的内容
作用:通过该函数可以获取一个上下文,从而实现工程自动化(遍历文件夹的文件,从中获取指定文件,自动导入模块)。在前端工程中,如果一个文件夹中的模块需要频繁引用时可以使用该中方式一次性引入
语法:let webf = require.context('文件路径',布尔值,正则)
返回值: 1 webf.keys() 返回一个数组,由匹配成功的文件所组成的数组 2 webf(路径).default 获取到路径中导出的模块
手动合并reducer
// 合拼reducer import {combineReducers} from 'redux' // combineReducers import CartReducer from './CartReducer' import meReducer from './meReducer' //作用:合拼reducer //语法: let reducers = combineReducers({属性:各自的reducer,属性:各自的reducer}) let reducers = combineReducers({ CartReducer, meReducer }) export default reducers
工程化处理reducer 合拼
/* combineReducer 作用: 合并 reducer 数据实现模块化 语法:let reducers=combineReducers({属性:各自的reducer, 属性:各自的reducer}) */ // 工程化处理Reducer 合拼 import { combineReducers } from "redux"; // combineReducers import CartReducer from "./CartReducer"; import MeReducer from "./MeReducer"; // 在这里引入各自的reducer // 处理方法 =》 自动引入reducer 自动合拼reducer // 1 在reducers文件夹下创建一个 reducer 文件 =》 再给我 合拼成reducer // 1 webpack =》 require.context =》自动获取到文件中的暴露内容 // 语法:require.context('文件路径',布尔值,正则) // requeire.context('文件路径',布尔值,正则) => 返回值 (是webpack)实例方式 // 两个方法 1. webf.keys()=>['文件路径',布尔值,正则] // 2.获取到它的内容 webf(路径).default let webf = require.context("./", true, /\.js/); let webfList = webf.keys(); // console.log(webfList); // 删除自身 index.js let index=webfList.findIndex((item,index)=>{ return item=='./index.js' }) webfList.splice(index,1) // console.log(webfList); // 将webfList合并成一个对象 let objs={}; webfList.forEach((item,index)=>{// 文件路径 ./ CartReducer .js // console.log(webf(item).default); // 处理属性 = item let items=item.replace('./','').replace('.js','') // console.log(items) objs[items]=webf(item).default }) // console.log(objs) // 作用:合并reducer // 语法:let reducers=combineReducers({属性:各自的reducer,属性:各自的reducer}) let reducers = combineReducers(objs); export default reducers;
五、bindActionCreators 自动触发reducer
作用:实现自动派发,实现行为 reducer 处理方法一一对应
语法:let 对象 = bindActionCreators({属性:属性值是一个方法},store.dispatch),属性值是一个方法 => 就是你的reducer中的方法
实现步骤:
/* 五:bindActionCreators bindActionCreators => 自动触发reducer => 你想要触发 语法:let 对象 =bindActionCreators({属性:属性值是一个方法},dispatch) 属性值是一个方法=》 就是你的reducers中的方法 使用: 1 实现reducer 和他的行为一一对应 2 使用 bindActionCreators 来实现 2.1 语法 bindActionsCreators({就是你的reducer 和 使用的行为对应},dispatch) 全部触发我的模板中的reducer 行为 1 我的模块reducer 有多少个行为 2 我的模块中add */ import { bindActionCreators } from "redux"; import store from "../index"; // bindActionCreators => 自动触发reducer => 你想要触发 // 语法 let对象 =bindActionCreators({属性:属性值是一个方法},dispatch),属性值是一个方法 =》就是你的reducer中的方法 // 创建方法 let meAdd = () => { return { // 行为 =》 actions type: "add", }; }; let meSub = () => { return { type: "sub", }; }; let meActions = bindActionCreators({ meAdd, meSub }, store.dispatch); export default meActions;
引入这个自动派发的方法 :直接使用
import logo from './logo.svg'; import './App.css'; //来到组件 import store from './store/index' import {useState} from 'react' //使用 自动派发 import meActions from './store/actions/meActions' function App() { // 1获取到仓库中的数据 console.log(store.getState()); // let age = store.getState().meReducer.age let [age,setAge] = useState(store.getState().meReducer.age) // 3引入我们这个自动派发的方法 =》直接使用 const changeAge = ()=>{ console.log( meActions); // store.dispatch({type:'add'}) //触发reducer meActions.meAdd() setAge(store.getState().meReducer.age) } return ( <div className="App"> <h2>我的年龄{age}</h2> <button onClick={()=>changeAge()}>修改仓库选中数据</button> </div> ); } export default App;
六、React Redux
1、为什么应该使用React-Redux?
因为React是一个独立的库,可以与React、Vue、Angular一直使用,但是它们是相互独立的;
如果想要同时使用 Redux 和 React,应该使用 React-Redux 来绑定这两个库
react-redux是连接react和redux 的桥梁,让react中使用redux时低耦合,方便快捷 react-redux 提供了两个 api
作用:提供全局组件和hooks,在父级组件提供仓库组件,在自己组件中获取到仓库的数据
Provider 为后代组件提供 store
connect 为组件提供数据和变更⽅法
核心:为我们react项目提供的一个组件,两个hooks
组件:Provider 1 作用:在父级组件中提供数据 ,其他的子集组件就可以获取到;
2 在父组件中提供了数据 store;
hooks:
useSelector 1 作用:在组件中获取仓库中的数据,再通过useState修改数据方法,让数据更新
2 语法:useSelector(state => { return 返回值}) // 返回 在仓库中获取的数据
useDispatch 1 作用:可以获取到更新组件的dispatch,先触发reducer,
2 语法:let dispatch=useDispatch(); dispatch({type:'add'});
2、在项目中使用redux
安装react-redux
npm install react-redux
2.在入口文件中使用Provider提供仓库store
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import { Provider } from 'react-redux'; import store from './store'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <Provider store={store}> {/* 在父组件中提供数据 */} <App /> </Provider> );
3.useSelector使用
4.useDispatch使用
/* react-redux 作用 提供 1 组件 =》 在子级组件提供仓库组件,在自己组件中获取到仓库数据 2 hooks useSelector => 得到仓库中的数据 // 语法 useDispatch 作用:可以获取到更新组件的dispatch;触发 reducer =》 语法 useDispatch() => dispatch() */ // 使用 // 在自己组件中获取到仓库中的数据 =》 使用它提供的两个hooks import {useSelector,useDispatch} from 'react-redux' // useSelector(state=>{返回值}) =》返回值 得到仓库中的数据 // useDispatch 触发redcuer =》 语法 useDispatch()=> 的返回值就是 dispatch() // 作用:获取到可以更新组件的dispatch function App(){ let age=useSelector(state=>{ // state是来自父组件的store数据 return state.MeReducer.age }) let dispatch=useDispatch() // 1 先触发reducer,获取到仓库中的数据,再通过useState修改数据方法,让数据更新 console.log(age,'组件重新创建'); return( <div> <h2>我的年龄{age}</h2> <button onClick={()=>{dispatch({type:'add'})}}>修改仓库</button> </div> ) } export default App /* 总结:react-redux 作用:让仓库和react项目进行关联 它为react项目提供了一个组件(Provider),两个hooks(useSelector、useDispatch) Provider: 在父级组件中提供数据,其他的自己组件就可以获取到 useSelector:在组件获取到仓库中的数据 useDispatch:先触发reducer,获取到仓库中的数据,再通过useState修改数据,让数据更新 */
七、异步actions
1、为什么需要处理异步?
因为reducer 只能处理同步问题,但是我们在工作中,可能需要在仓库中发生请求,获取到异步的数据
2、异步actions作用?
1)在仓库中获取异步收据 2)触发reducer 修改仓库中的数据
3、实现异步actions?
在store文件夹下创建一个 actions 文件夹,实现 异步actions 和各自的reducer 一一对应
//我的模块中 异步处理 import axios from 'axios' import store from '../index' // 定义异步处理方法 //根据actions作用来进行定义 =》1 获取到异步数据 2 触发reducer //定义异步处理方法 // 1 是一个方法 // 2 获取到异步数据 // 3 触发reducer => store export function getAgeSub(){ //1获取到异步数据 function getData(){ return axios.get('').then(res=>{ //后端给的数据 let a = 100 return a }) } // 2触发reducer return async()=>{ // 1获取到异步数据 let data = await getData() console.log(data); // 2 触发reducer =>将异步数据传递给 reducer console.log('触发reducer'); store.dispatch({type:'add',data }) } } // getAgeSub() //总结 定义actions //1 获取到异步数据 //2 触发reducer //3 知道执行的获取到异步数据,再 执行reducer //定义异步actions => 函数劫持 //高阶函数=》 1 这个函数的参数是一个函数 或者 这个函数的返回值是一个函数 // 函数劫持 =》我在处理某个逻辑之前,要做一些操作,我们把这个方法叫做函数劫持
4 、在组件中使用 dispatch 触发异步actions
会报错 => 需要使用 1 中间件 2 redux-thunk
redux-thunk =》 作用1:处理异步action =》 给 异步action触发方法,第一个参数 就是dispatch
5、配置中间件 =》redux-thunk
在store/index.js 文件中进行配置
安装redex-thunk
npm install redux-thunk
// 引入中间件 import {createStore,applyMiddleware} from 'redux' import reducers from './reducers' // 引入'redux-thunk' import ReduxThunk from 'redux-thunk' let store = createStore(reducers,applyMiddleware(ReduxThunk)) //applyMiddleware(ReduxThunk) =>1处理组件中 dispatch()这个方法内容可以写 方法 // 2 异步actions 返回的处理方法 的第一次参数就是dispatch export default store
6、在其他组件中触发异步actions
创建 异步actions 返回的处理方法 的第一次参数就是dispatch
export function getAgeReduce(){ //1获取到异步数据 function getData(){ return axios.get('').then(res=>{ //后端给的数据 let a = 100 return a }) } // 2触发reducer return async(dispatch)=>{ //第一个参数 就是 dispatch // 1获取到异步数据 let data = await getData() console.log(data); // 2 触发reducer =>将异步数据传递给 reducer console.log('触发reducer'); dispatch({type:'reduce',data }) } }