谈谈我自己对redux的理解
Redux是一个JavaScript状态管理库,用于管理Web应用程序中复杂的UI组件的状态。它采用可预测和可维护的方式来跟踪应用程序中的所有组件的状态,并提供一种统一的方法来更新这些状态。
Redux的核心概念是store(仓库)和action(操作)。当应用程序的状态发生变化时,Redux会创建一个新的action对象,并将其发布到store中。然后,reducer函数会被调用来更新store中的状态。最后,组件通过订阅store中的action来响应状态的变化。
Redux的使用场景包括但不限于以下几个方面:
- 大型单页应用程序(SPA):在SPA中,每个组件都可能需要访问共享的状态,而Redux可以帮助管理这些状态,确保它们在整个应用程序中保持一致。
- 复杂UI组件:当一个UI组件需要依赖于其他组件的状态时,使用Redux可以确保状态的正确更新,并且不会破坏应用程序的一致性。
- 跨多个页面的应用程序:在多页面应用程序中,不同的页面可能需要共享相同的数据和状态。使用Redux可以确保这些状态在整个应用程序中保持一致。
- 需要进行大规模重构的应用程序:当应用程序需要进行大规模重构时,使用Redux可以使状态管理更加简单和可预测。
下面我们来看一下redux具体怎么用的。以下例子将在类组件,函数组件,搭配useEffect,useContext,context。
我们总共需要5个文件分别是context.js,Vote.jsx,VoteMain.jsx,VoteFooter.jsx,以及入口文件index.js。
首先,在React中,Context(上下文)是一种用于跨组件传递数据和状态的机制。它允许您在整个应用程序中共享数据和状态,而不必在每个组件中重复编写相同的代码。
Context API提供了一种创建上下文对象的方法,该对象可以在应用程序中的任何地方使用。通过将Context对象传递给子组件,您可以确保它们访问的数据和状态是一致的,并且不会污染其他组件的数据和状态。
context.js,代码如下:
import React from "react";
const ThemeContext = React.createContext();
export default ThemeContext;
祖先组件就是咱们的入口文件index.js,父组件是Vote.jsx,VoteMain.jsx和VoteFooter.jsx是子组件,祖先代码如下。
祖先组件index.jsx如下
root.render(
<ConfigProvider locale={zhCN}>
<Vote></Vote>
</ConfigProvider>
)
父组件Vote.jsx代码如下:
import React,{useContext,useState,useEffect} from "react";
import VoteFooter from "./VoteFooter";
import VoteMain from "./VoteMain";
import './Vote.less'
const Vote = function Vote() {
return(
<div className="vote-box">
<div className="header">
<h2 className="title">React真是个好框架</h2>
<span className="num">0</span>
</div>
<VoteMain></VoteMain>
<VoteFooter></VoteFooter>
</div>
)
}
export default Vote;
子组件VoteMain[类组件写法]代码如下:
import React from "react"
import ThemeContext from './context'
class VoteMain extends React.Component{
render(){
return(
<div className="main">
<p>支持人数:10人</p>
<p>反对人数:10人</p>
</div>
)
}
}
export default VoteMain;
子组件VoteFooter代码如下:
import { Button } from "antd";
const VoteFooter = function VoteFooter() {
return (
<div className="footer">
<Button type="primary">
支持
</Button>
<Button type="primary" danger>反对</Button>
</div>
)
}
export default VoteFooter;
现在我想要通过祖先组件拿到redux的值,然后再传递到子组件中,我该如何操作呢?首先祖先组件要传值到后代组件,我们可以props层层传递,那么还可以通过context上下文来获取,上文我们写了context.js的代码,导出了 ThemeContext,那么我们就可以使用了,通过ThemeContext.Provider,在祖先组件中,将父组件进行包裹起来。
root.render(
<ConfigProvider locale={zhCN}>
<ThemeContext.Provider>
<Vote></Vote>
</ThemeContext.Provider>
</ConfigProvider>
)
接下来就看一下redux文件具体怎么写。redux是可以用来存储公共的一些状态就相当于是个仓库一下,那么在src目录下创建store文件夹,然后创建index.js,这个就是咱们的redux文件。
对于redux的使用,分5步来,都是特定的套路
- 创建全局公共的容器 const store = createStore()
- 在组件内部获取公用的状态信息,然后渲染 store.getState()
- 把”让组件可以更新“的方法放在公共容器的事件池中 store.subscribe(函数)
- 记住,创建容器的时候要传递reducer const store = createStore(reducer)
- 根据type进行派发任务,通知reducer执行修改的状态
下面的这段代码是redux的整个文件,创建了容器,然后创建了reducer函数,里面就是存放的一些数据方法也就是state,action,最近进行传递reducer,最后导出。
import {createStore} from 'redux'
let initial = {
supNum:10,
oppNum:5
}
/** 管理员:修改STORE容器中的公共状态 */
//这边需要定义reducer函数,传参也是固定的state跟action
const reducer = function reducer(state = initial,action){
/**
* state:存储STORE容器中的公共状态【最开始没有的时候,赋值初始状态initial】
* action:每一次基于dispatch派发的时候,传递进来的行为对象
【要求必须具备type属性,存储派发的行为标识】📢📢📢📢📢📢很重要,通过type来进行dispatch派发
* 为了接下来的操作中,我们操作state,不会直接修改容器中的状态
【要等到最后return的时候,我们需要先克隆】state = {...state} 📢📢📢📢📢📢很重要
* 接下来我们需要基于派发的行为标识,修改STORE容器中的公共状态信息
*
*/
state = {...state}
//这边也可以改为if....else...的写法
switch(action.type){
case "VOTE_SUP":
state.supNum++
break;
case 'VOTE_OPP':
state.oppNum++
break;
default:
} //匹配不同的操作类别或选择器,比如匹配动态或类似的操作类别或选择器,如果没有特定的匹配选择器,则应将action转换为type匹配的主题名称或选择器名称,如果匹配,则将其转换为具有相同主题名称或选择器的新状态。这些主题名称或选择器名称应在store.js中列出。 (请
return state;
}
//
const store = createStore(reducer);
export default store;
下面在祖先文件index.jsx中获取到这个store的公共值
<ConfigProvider locale={zhCN}>
//这边也是固定写法,因为要获取的是store的值,所以这边的value也就是传递的是store
<ThemeContext.Provider value={{store}}>
<Vote></Vote>
</ThemeContext.Provider>
</ConfigProvider>
现在在Vote.jsx组件中进行获取store中的状态值,因为Vote组件是用函数组件写的,所以用HOOK函数useContext
import React,{useContext,useState,useEffect} from "react";
import VoteFooter from "./VoteFooter";
import VoteMain from "./VoteMain";
import './Vote.less'
//上下文特定写法,不要纠结 一定要注意咱们现在的值都是从祖先组件中拿取的
import ThemeContext from "./context";
const Vote = function Vote() {
//上下文特定写法,不要纠结
const {store} = useContext(ThemeContext)
console.log(store)
这边打印看到已经拿到store的值了,是个对象
1. Object
1. 1. @@observable: ƒ observable()
1. dispatch: ƒ dispatch(action)
1. getState: ƒ getState()
1. replaceReducer: ƒ replaceReducer(nextReducer)
1. subscribe: ƒ subscribe(listener)
1. [[Prototype]]: Object
// 获取容器中的公共状态
let {supNum,oppNum} =store.getState() 这边也拿到了store中的初始值{supNum: 10, oppNum: 10}
【这边可能有人有疑问了,这是什么意思?说到底,这边的状态函数就是单纯为了让组件进行更新的一个方法,把这个update方法
放到事件池中,让这个来促使组件的更新,只要保证每次的num值与上一次的不一样就好,这边就是这个作用,因为我们看到了
store.subscribe()】
// 组件第一次渲染完毕后,把让组件更新的方法,放在STORE的事件池中
let [num,setNum] = useState(0)
const update = ()=>{
setNum(num+1)
}
useEffect(()=>{
let unsubscribe = store.subscribe(update)
return()=>{
unsubscribe(); //在上一次组件释放的时候,把上一次放在事件池中的方法移除掉
}
},[num])
【或者还可以其他的写法,可以不用像上面那么麻烦,还是只在第一次渲染完往事件池中加入一个方法即可,
必须保证这个方法执行,修改的状态值和之前的状态值不一样!!时间戳或者随机数,请看下面的写法,这个也是为了能够让组件更新】
let [_,setNum] = useState(0)
useEffect(()=>{
store.subscribe(()=>{
setNum(+new Date)
})
})
return(
<div className="vote-box">
<div className="header">
<h2 className="title">React是真尼玛的难学啊</h2>
<span className="num">{supNum+oppNum}</span>
</div>
<VoteMain></VoteMain>
<VoteFooter></VoteFooter>
</div>
)
}
export default Vote;
最后我们再看一下dispatch 的派发,这是任务方法,咱们到VoteFooter.jsx中
import React,{useContext} from "react";
import { Button } from "antd";
//同样用到上下文,一定要注意咱们现在的值都是从祖先组件中拿取的
import ThemeContext from "./context";
// 在方法中不需要获取到公共的状态信息,而是获取方法 dispatch
const VoteFooter = function VoteFooter() {
const {store} = useContext(ThemeContext)
return (
<div className="footer">
<Button type="primary" onClick={()=>{
store.dispatch({
type:'VOTE_SUP' //这边就是通过type这个标识来获取到底要派发哪个任务了
})
}}>
支持
</Button>
<Button type="primary" danger onClick={()=>{
store.dispatch({
type:'VOTE_OPP'
})
}}>反对</Button>
</div>
)
}
export default VoteFooter;
写了这么多,最后总结一下具体的代码编写
- 创建store,规划出reducer[当中的业务也就是action这些可以以后开发中不断完善,但是最开始reducer架子要有]
- 在入口中,基于上下文对象,把store放入到上下文中;需要用到store的组件从上下文获取
- 组件中基于store,完成公共装药的获取和任务方法的派发,重点重点!!!!使用到公共状态的组件必须向store事件池中加入让组件更新的方法,只有这样才可以确保公共状态改变,组件更新
每个人对redux的理解都是大同小异,只要是有利自己理解那都是好方法!!!如果错误还请各位指出!!!
转载自:https://juejin.cn/post/7237065395941638203