一、Redux概述
1.1 什么是redux
Redux是一个用于JavaScript状态容器,提供可预测的状态管理;
Redux可以构建一致化的应用,运行于不同的环境,易于测试;
Redux除了和React一起使用,还支持其他界面库,而且体积小精悍;
1.2 reudx设计初衷
JavaScript单页面开发日趋复杂化,javaScript需要管理更多的state状态。这些state可能包括服务器响应、缓存数据、本地生成未持久化到服务器的数据,也包括ui状态;
管理不断变化state非常麻烦,如果一个model的变化会引起另一个model变化,那么当view变化时,就可能引起对应model以及另一个model的变化,依次可能会引起另一个view的变化,所以就会产生混乱;
而redux就是为了解决这个问题;
1.3 redux三大核心
1、单一数据源
整个应用的state被存储在一颗object tree中,并且这个object tree只存住一个唯一一个store中
2、state是只读的
唯一改变state的方法就是触发action、action是一个用于描述已经发生事件的普通对象;
这样确保了视图和网络请求都不能直接去修改state,相反,他们只能表达要修改的意图,因为所有的修改都被集中化处理,并且严格按照一个接一个的顺序执行
store.dispatch({type:'COMPLETE_TODO',index:1})
3、使用纯函数来执行修改
为了描述action如何改变state tree,你需要去编写reducers
Reducers只是一些纯函数,它接收先前的state和action,并且返回新的state,可以复用、可以控制顺序、传入附加参数;
二、Redux组成
2.1State-状态
就是我们传递的数据,那么我们在用React开发项目的时候,大致可以把state分为三类;
- DommainDate:可以理解成服务器端的数据,比如:获取用户的信息,商品的列表等等
- UI State:决定当前UI展示的状态,比如:弹框的显示和隐藏,受控组件等
- App State:App级别的状态,比如:当前是否请求loading,当前路由信息等可能被多个和组件去使用得到的状态
2.2Action-事件
Action是把数据从应用传到store的载体,它是store数据的唯一来源 ,一般来说,我么可以通过store.dispatch()将action传递给store
Action特点:
- Action本质就是一个JavaScript的普通对象
- Action对象内部必须要有一个type属性来表示要执行的操作
- 多少情况下这个type会被定义成字符串常量
- 除了type字段之外,action的结构随意进行定义
- 而在我们的项目中,更多喜欢用action创建函数
- 只是描述了有事情要发生,并没有描述如何去更新state
//action
{
type:"字符串常量",
info:{...},
isLoading:true,
...
}
//action创建函数
function addAction(params){
//返回一个action对象
return{
type:"add",
...params
}
}
Reducer
Reducer本质就是一个函数,他用来响应发送过来的action,然后经过处理,把state发送给Store的
注意:在Reducer函数中,需要return返回值,这样store才能接收到数据,函数会接收两个参数,第一个参数是初始化state,第二个参数是action
const initState = {...};
rootReducer = (state = initState.action) => {...return{...}};
2.3 Store
Store就是把 action 与reducer联系到一起的对象
主要职责:
- 维持应用的state
- 提供getState()方法获取state
- 提供dispatch()方法发送action
- 通过subscribe()来注册监听
- 通过subscribe()返回值来注销监听
improt { createStore } from "redux";
const store = createStore(传递reducer);
三、案例
3.1准备工作
- 构建react项目
npx create-react-app redux-demo
- 删除多余文件
- 在pages目录下创建Home组件
- 编写一个简单的结构样式
<button>发送一个action</button>
- 在App.js中引入这个组件
- 安装redux
yarn add redux
项目结构如图:
page>home>index.js
import React from "react";
const Home = () =>{
return (
<button>点我发送action</button>
)
}
export default Home
App.js
import React from "react";
import Home from "./pages/home/index"
function App() {
return (
<div className="App">
<Home/>
</div>
);
}
export default App;
3.2创建一个Action
- 在根目录下创建一个文件夹action
- 在该目录下创建一个index.js文件,用来构建Action
const sendAction = () => {...};
- 在action创建函数里面 利用return,返回一个action对象,注意需要携带type属性
const sendAction = () => {
return { type: "send_action", value: "发送了一个action" };
};
- 把这个函数导出
module.exports = {sendAction}
src>action>index.js
const sendAction = () => {
return {
type: "sned_type",
value: "一个action",
};
};
module.exports = { sendAction };
3.3创建一个Reducer
- 在根目录下创建一个文件夹reducer
- 在该目录下创建一个index.js文件,用来构建reducer,注意reducer要接收两个参数
const rootReducer = (state,action)=>{...}
- 第一个参数是默认状态,我们可以定义一个初始化的state,然后进行赋值
const initState = {value:"默认值"}
const rootReducer = (state = initState.action) =>{...}
- 在函数里面判断第二个参数action的type值是否是我们发送的
- 如果是的话,我们可以通过return返回新的state
- 把reducer进行导出
src>reducer>index.js
const initState = {
value: "默认值",
};
const reducer = (state, action) => {
switch (action.type) {
case "send_type":
return Object.assign({}, state, action);
default:
return state;
}
};
module.exports = { reducer };
3.4 创建Store
- 在根目录下创建一个文件夹store
- 在该目录下创建一个index.js文件,用来构建store,注意createStore函数里面第一个参数接收的是reducer"
import { legacy_createStore as createStore } from "redux";
import { reducer } from "../reducer";
const store = createStore(reducer);
export default store;
- 我们需要导入刚刚创建的reducer,然后设置到函数里面去
- createStore的返回值就是我们构建好的store,然后进行导出
因为createStore 已经被弃用,使用 legacy_createStore as createStore
3.5在Home组件开始使用
- 给页面的button按钮绑定一个点击事件
- 在组件一加载完毕的时候我们通过stroe来进行 监听器的注册,返回值可以用来注销监听
this.unSubbsribe = store.subscript{()=>{...}}
在点击事件处理函数中,通过store.dispatch来发送一个action
handleClick = {} => {store.dispatch(sendAction)}
src>pages>home
import React, { useEffect } from "react";
import store from "../../store";
import { sendAction } from "../../action";
const Home = () =>{
const handleClick = () =>{
const action = sendAction()
store.dispatch(action)
}
useEffect(()=>{
store.subscribe(()=>{
console.log(store.getState())
})
},[])
return (
<>
<button onClick={handleClick}>点我发送action</button>
<div>{store.getState().value}</div>
</>
)
}
export default Home