Redux学习
1.Redux是什么
1)redux是一个独立专门用于做状态管理的JS库 (并不是react插件库)
2)它可以用于react、vue等项目中,但基本上与react配合使用。
3)作用:集中式管理react应用中多个组件共享的状态 (单个组件也能管理)
概述:Redux是一个用于JavaScript的状态容器,提供可预测化的状态管理。容器就是用来存储数据的。可以构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。并且它只有2kB。
这里有一个redux的原理图: 注意这个action包含两个值。在下面会具体讲到,记得回来看这个图。
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就是把 action 和 reducer 联系到一起的对象
主要职责:
- 维持应用的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回调函数:更新组件、重新渲染组件
再次对应这个图看,应该好理解一些吧。
3.Redux入门案例
先写一个入门案例,帮助我们理解吧!
1.准备工作
-
构建 react 项目
npx create-react-app redux-demonpx的作用:临时下载create-react-app 脚手架工具,并使用它创建应用,应用创建完成后呢,删除临时下载的脚手架工具
-
删除多余的文件
找到 src 目录下,只留下App.js,index.css,index.js即可,然后到文件中删除引用到其他文件的地方。App.js留下最外层div即可。
-
在 src下创建 pages 目录,pages下再创建 Home 组件(Home文件夹,里面放一个index.js)
-
到上面创建的index.js中 编写一个简单的结构样式 一个按钮
import React from "react"; //导出我们的组件,用 类组件 的方式声明 继承 React.Component export default class Home extends React.Component { //在实现组件的时候,必须要有一个render方法,代表 要渲染什么内容 render(){ return ( <button>点我发送action</button> ) } } -
在 App.js 中引入这个组件
import React from "react"; import Home from "./pages/home"; function App() { return ( <div className="App"> <Home/> </div> ); } export default App; -
安装 redux
yarn add reduxnpm 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就可以在页面看到效果啦!