Redux学习

110 阅读7分钟

Redux学习

1.Redux是什么

1)redux是一个独立专门用于做状态管理的JS库 (并不是react插件库

2)它可以用于react、vue等项目中,但基本上与react配合使用。

3)作用:集中式管理react应用中多个组件共享的状态 (单个组件也能管理)

概述:Redux是一个用于JavaScript的状态容器,提供可预测化的状态管理。容器就是用来存储数据的。可以构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。并且它只有2kB。

这里有一个redux的原理图: 注意这个action包含两个值。在下面会具体讲到,记得回来看这个图。

redux原理.webp

2.Redux的组成

在学习下面之前,先认识 store 是一个对象。

2.1 State-状态

就是我们传递的数据,那么我们在用React开发项目的时候,大致可以把State分为三类

  • DomainDate:可以理解为服务器端的数据,比如:获取用户的信息,商品的列表等等
  • UI State:决定当前UI展示的状态,比如:弹框的显示隐藏,受控组件等等
  • App State:App级别的状态,比如:当前是否请求loading、当前路由信息、可能会被多个组件使用的状态等等

2.1 Action-事件

Action是把数据从应用传到store的载体它是store数据的唯一来源,一般来说,我们可以通过store.dispatch()将action传递给 store。

要把数据传给谁,就让谁.dispatch(action)

Action的特点:

  • Action的本质就是一个JavaScript的普通对象

  • Action对象内部必须要有一个type属性来表示要执行的动作

  • 多数情况下,这个type会被定义成字符串常量

  • 除了type之外,action的结构随意进行定义

  • 我们会遵循模块化开发的思想,在我们的项目中,更多的喜欢单独创建一个action的文件,在里面构建action对象

  • 只描述了有事情要发生,并没有描述如何去更新state

    举个栗子:

     //像这样就是一个action
     {
         type:'add', //描述了是加法
         number: 1,
     }
     ​
     //而基于模块化开发思想,通常会使用 action创建函数 来创建action,这里我平时比较习惯用es6语法写函数
     const addAction = (params)=>{
         //返回一个action对象
         return {type:'add',...params}
     }
    

2.3 Reducer

Reducer本质就是一个函数,它用来响应发送过来的actions,然后经过处理,把 新的state 发送给 store

*注意:*在Reducer函数中,一定要有return返回值,这样 store 才能接收到新数据。函数会接收两个参数,第一个参数是初始化state,第二个参数是action。

2.4 Store

Store就是把 actionreducer 联系到一起的对象

主要职责:

  • 维持应用的state
  • 提供 getState() 方法获取 state
  • 提供 dispatch() 方法发送 action
  • 通过 subscribe() 来注册监听
  • 通过 subscribe() 返回值来注销监听
 import { createStore } from 'redux'
 const store = createStore(reducer) //reducer由我们自己另外编写

ok,接着往详细一点讲

getState() : 获取状态

dispatch(action) :分发 action,触发 reducer 调用,产生新的 state

subscribe(listener) :注册监听,当产生新的state时,自动调用 listener回调函数:更新组件、重新渲染组件

再次对应这个图看,应该好理解一些吧。

redux原理.webp

3.Redux入门案例

先写一个入门案例,帮助我们理解吧!

1.准备工作

  1. 构建 react 项目

    npx create-react-app redux-demo

    npx的作用:临时下载create-react-app 脚手架工具,并使用它创建应用,应用创建完成后呢,删除临时下载的脚手架工具

  2. 删除多余的文件

    找到 src 目录下,只留下App.js,index.css,index.js即可,然后到文件中删除引用到其他文件的地方。App.js留下最外层div即可。

  3. 在 src下创建 pages 目录,pages下再创建 Home 组件(Home文件夹,里面放一个index.js)

  4. 到上面创建的index.js中 编写一个简单的结构样式 一个按钮

     import React from "react";
     ​
     //导出我们的组件,用 类组件 的方式声明 继承 React.Component
     export default class Home extends React.Component {
         //在实现组件的时候,必须要有一个render方法,代表 要渲染什么内容
         render(){
             return (
                 <button>点我发送action</button>
             )
         }
     }
    
  5. 在 App.js 中引入这个组件

     import React from "react";
     import Home from "./pages/home";
     ​
     function App() {
       return (
         <div className="App">
           <Home/>
         </div>
       );
     }
     ​
     export default App;
    
  6. 安装 redux yarn add redux npm i redux

2.创建一个Action

  • 在根目录下创建一个文件夹 action,不直接定义在组件内部,降低action与组件的耦合度,提高复用性。

  • 在该目录下创建一个index.js文件,用来 构建Action const sendAction = ()=>{...}

  • 在action创建函数里面 利用 return,返回一个action对象,注意需要携带type属性

    const sendAction = ()=>{return {type:"send_type",value:"我是一个action"}}

  • 把这个action创建函数进行导出,这样哪个页面想获取action对象直接导入即可 module.exports = {sendAction}

 //这是 action 的构建函数
 const sendAction = () => {
     //返回一个 action 对象
     return {
         type:"send_type",
         value:"我是一个action"
     }
 }
 ​
 module.exports = {
     sendAction
 }

3.创建一个Reducer

  • 在根目录下创建一个文件夹 reducers ,专门存放reducer函数

  • 在这个目录下创建一个index.js文件,用来 构建reducer,注意reducer要接收两个函数

    const rootReducer = (state,action)=>{...}

  • 第一个参数是默认状态,我们可以定义一个初始化的state,然后进行赋值

    const intState = {value:"默认值"}

    const rootReducer = (state = initState,action) => {...}

  • 在函数里面判断第二个参数action的type值是否是我们发送的

  • 如果是的话,我们可以通过return返回新的 state

  • 导出reducer

 //创建 reducer函数,处理 action
 ​
 const initState = {
     value: '默认值'
 }
 //设置初始化值,如果没有state传过来的话,就用这个初始值
 const reducer = (state = initState,action) => {
     switch (action.type){
         case 'send_type':
             //使用assign将两个对象进行组合
             return Object.assign({},state,action)
         default:
             return state
     }
 }
 ​
 module.exports = {
     reducer
 }

4.创建Store

  • 在根目录下创建一个文件夹 store

  • 在该目录下创建一个 index.js 文件,用来 构建store,注意 createStore 函数里面第一个参数接收的是reducer

     import { createStore } from "redux"
     const store = createStore(reducer) //这里的reducer就是我们上面创建的reducer了 同样用import拿到
    
  • 我们需要导入 刚刚创建的 reducer,然后设置到函数里面去

  • createStore的返回值就是我们构建好的store,然后进行导出

 //这里呢我们导入 import {createStore} from 'redux' 的时候会发现,createStore被移除了
 //这里就让我发现 redux学完之后,得去学学新的 reduxToolkit,这个接下来会进行学习
 import {legacy_createStore as createStore} from 'redux'
 //导入我们的reducer
 import { reducer } from '../reducers'
 ​
 //构建 store
 const store = createStore(reducer)
 ​
 export default store

5.在Home组件使用

  • 给页面的button绑定一个点击事件,点击发送action

  • 在组件加载完毕的时候我们通过store来进行监听器的注册,返回值可以用来注销监听。监听是为了接收新的状态,而如果组件销毁则注销监听,防止内存泄漏。

    this.unSubbscribe = store.subscribe(()=>{...})

  • 在点击事件处理函数中,通过store.dispatch来发送一个action

    handleClick = () =>{store.dispatch(sendAction())}

    备注里有很多细节

 import React from "react";
 //导入store
 import store from "../../store";
 //导入action构建函数
 import { sendAction } from "../../action";
 ​
 //导出我们的组件,用 类组件 的方式声明 继承 React.Component
 export default class Home extends React.Component {
     handleClick = ()=>{
         //调用sendAction() 拿到action对象
         const action = sendAction()
         //利用 store 发送一个 action 需要参数 action
         store.dispatch(action)
     }
 ​
     //当组件一加载完毕的时候 进行监听操作
     componentDidMount(){
         store.subscribe(()=>{
             this.setState({}) //这里setState只是为了触发render刷新页面,不需要传东西
         })
     }
 ​
     //在实现组件的时候,必须要有一个render方法,代表 要渲染什么内容
     render(){
         return (
             <>
                 <button onClick={this.handleClick}>点我发送action</button>
                 <div>{store.getState().value}</div>
             </>
         )
     }
 }

ok!执行npm start就可以在页面看到效果啦!