一、redux使用
1、安装依赖
yarn add redux
or
npm i redux
2、创建actions文件
- 创建 store 目录
- 创建 actions.js 文件
// actions.js
// 每次累加一
export const addOne = () => {
return {
type: "addOne",
};
};
// 每次递减一
export const subOne = () => {
return {
type: "subOne",
};
};
// 每次累加多个
export const addMany = (num) => {
return {
type: "addMany",
payload: num,
};
};
// 每次递减多个
export const subMany = (num) => {
return {
type: "subMany",
payload: num,
};
};
3、创建reducer文件
- 创建 reducer 文件
// reducer.js
// 每次初始化项目时都会执行该方法,且action随机生成,故每次都走default分支
// 当调用dispatch方法进行数据修改时,也会调用该方法
export const reducer = (state = 1, action) => {
switch (action.type) {
case "addOne":
return state + 1;
case "subOne":
return state - 1;
case "addMany":
return state + action.payload;
case "subMany":
return state - action.payload;
default:
return state;
}
};
4、创建index 文件
- 创建 index 文件
// 引入redux
import { createStore } from "redux";
import { reducer } from "./reducer";
const store = createStore(reducer);
export default store;
5、页面中使用
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import store from "./store/index";
import { addMany, addOne, subMany, subOne } from "./store/actions";
function T() {
console.log("store", store);
// 获取状态
const [data, setData] = useState(() => {
return store.getState();
});
return (
<div>
<h2>最新状态:{data}</h2>
<button
onClick={() => {
store.dispatch(addOne());
console.log("data", store.getState());
setData(store.getState());
}}
>
累加一
</button>
<button
onClick={() => {
store.dispatch(subOne());
console.log("data", store.getState());
setData(store.getState());
}}
>
累减一
</button>
<button
onClick={() => {
store.dispatch(addMany(20));
console.log("data", store.getState());
setData(store.getState());
}}
>
累加多个
</button>
<button
onClick={() => {
store.dispatch(subMany(50));
console.log("data", store.getState());
setData(store.getState());
}}
>
累减多个
</button>
</div>
);
}
const root = createRoot(document.getElementById("root"));
root.render(<T></T>);
二、react-redux简单使用
因为redux中每次修改数据,都要使用 setData去更新 state中的数据,从代码量来说相对冗余,故使用react-redux提供的hook更为方便,相当于vuex中的map辅助工具
1、安装依赖
// 如果你使用 npm:
npm install react-redux
// 或者你使用 Yarn:
yarn add react-redux
2.改造actions文件
export const addOne = () => {
return {
type: "addOne",
};
};
export const subOne = () => {
return {
type: "subOne",
};
};
export const addMany = (num) => {
return {
type: "addMany",
payload: num,
};
};
export const subMany = (num) => {
return {
type: "subMany",
payload: num,
};
};
// 名称
export const changeName = (name) => {
return {
type: "changeName",
payload: name,
};
};
3.改造reducer文件
export const reducer = (state = { num: 999, name: "李四" }, action) => {
switch (action.type) {
case "addOne":
return { ...state, num: state.num + 1 };
case "subOne":
return { ...state, num: state.num - 1 };
case "addMany":
return { ...state, num: state.num + action.payload };
case "subMany":
return { ...state, num: state.num - action.payload };
case "changeName":
return { ...state, name: action.payload };
default:
return state;
}
};
3.1 错误示范
export const reducer = (state = { num: 999, name: "李四" }, action) => {
switch (action.type) {
case "addOne":
state.num = state.num+1;
// 若直接返回state,则不会触发页面数据更新,react中对于复杂数据类型,必须改变堆地址,才能触发页面更新
return state;
default:
return state;
}
};
4.改造页面文件
1)将原本的文件进行组件抽取
import { addMany, addOne, changeName, subMany, subOne } from "./store/actions";
import store from "./store/index";
// 引入react-redux 获取store的值
import { useSelector, useDispatch } from "react-redux";
function App() {
const dispatch = useDispatch();
const num = useSelector((store) => {
return store.num;
});
const name = useSelector((store) => {
return store.name;
});
return (
<div>
<h2>最新状态num:{num}</h2>
<h2>最新状态name:{name}</h2>
<button
onClick={() => {
// store.dispatch(addOne());
dispatch(addOne());
console.log("data", store.getState());
}}
>
累加一
</button>
<button
onClick={() => {
// store.dispatch(subOne());
dispatch(subOne());
console.log("data", store.getState());
}}
>
累减一
</button>
<button
onClick={() => {
// store.dispatch(addMany(20));
dispatch(addMany(20));
console.log("data", store.getState());
}}
>
累加多个
</button>
<button
onClick={() => {
// store.dispatch(subMany(50));
dispatch(subMany(50));
console.log("data", store.getState());
}}
>
累减多个
</button>
<button
onClick={() => {
// store.dispatch(changeName("张三王五" + Math.random() * 100));
dispatch(changeName("张三王五" + Math.random() * 100));
console.log("data", store.getState());
}}
>
修改名称
</button>
</div>
);
}
export default App;
2)根文件,引入Provider
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import store from "./store";
// 引入react-redux 将store传递下去
import { Provider } from "react-redux";
function T() {
return (
<Provider store={store}>
<App></App>
</Provider>
);
}
const root = createRoot(document.getElementById("root"));
root.render(<T></T>);
三、react-redux 合并多个reducer
1、改造 actions 文件
// actions.js
export const add = () => {
return { type: "add" };
};
export const changeName = (name) => {
return { type: "changeName", payload: name };
};
2、改造 reducer 文件,引入合并方法 combineReducers
// reducer.js
import { combineReducers } from "redux";
const personInfo = (state = 10, action) => {
console.log("personInfo");
switch (action.type) {
case "add":
return state + 1;
default:
return state;
}
};
const animalInfo = (state = { name: "张三", age: 12 }, action) => {
console.log("animalInfo");
switch (action.type) {
case "changeName":
return { ...state, name: action.payload };
default:
return state;
}
};
export default combineReducers({ personInfo, animalInfo });
3、页面中使用
3.1 改造App文件
// App.js
import { useSelector, useDispatch } from "react-redux";
import { add, changeName } from "./store/actions";
const App = () => {
const dispatch = useDispatch();
const personInfo = useSelector((state) => {
console.log("state", state);
return state;
});
return (
<div>
<h2>这是app页面</h2>
<div>persinInfo:{JSON.stringify(personInfo)}</div>
<button
onClick={() => {
dispatch(changeName("王五" + Math.random() * 100));
}}
>
修改名称
</button>
<button
onClick={() => {
dispatch(add());
}}
>
修改数字
</button>
</div>
);
};
export default App;
3.2 改造根文件
// index.js
import React from "react";
import { createRoot } from "react-dom/client";
import store from "./store";
import App from "./App";
import { Provider } from "react-redux";
const root = createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App></App>
</Provider>
);
四、抽取常量,便于后期维护
将reducer.js文件和actions.js文件中的常量进行抽取
4.1 新建 actionTypes.js 文件
export const BASE_ADD = "base/add";
export const BASE_CHANGENAME = "base/changeName";
4.2 修改reducer.js
import { combineReducers } from "redux";
import { BASE_ADD, BASE_CHANGENAME } from "./actionTypes";
const personInfo = (state = 10, action) => {
console.log("personInfo");
switch (action.type) {
case BASE_ADD:
return state + 1;
default:
return state;
}
};
const animalInfo = (state = { name: "张三", age: 12 }, action) => {
console.log("animalInfo");
switch (action.type) {
case BASE_CHANGENAME:
return { ...state, name: action.payload };
default:
return state;
}
};
export default combineReducers({ personInfo, animalInfo });
4.3 修改actions.js
import { BASE_ADD, BASE_CHANGENAME } from "./actionTypes";
export const add = () => {
return { type: BASE_ADD };
};
export const changeName = (name) => {
return { type: BASE_CHANGENAME, payload: name };
};
五、redux 中间件thunk(异步操作中间件)
5.1 安装依赖
yarn add redux-thunk
5.2 注册插件
// store/index.js
import { createStore } from "redux";
import reducer from "./reducer";
import { applyMiddleware } from "redux";
// 导入异步 中间件 类似 vuex中的action
import thunk from "redux-thunk";
import logger from "redux-logger";
// 导入 事件日志 中间件
const store = createStore(reducer, applyMiddleware(thunk, logger));
export default store;
5.3 模拟异步操作
import { BASE_ADD, BASE_CHANGENAME } from "./actionTypes";
export const add = () => {
return { type: BASE_ADD };
};
export const changeName = (name) => {
return { type: BASE_CHANGENAME, payload: name };
};
export const handleAction = (id) => {
return (dispatch) => {
// 异步操作
setTimeout(() => {
console.log("你个老六");
dispatch(changeName("你个老六" + id));
}, 2000);
};
};
5.4 页面使用
import { useSelector, useDispatch } from "react-redux";
import { add, changeName, handleAction } from "./store/actions";
const App = () => {
const dispatch = useDispatch();
const personInfo = useSelector((state) => {
console.log("state", state);
return state;
});
return (
<div>
<h2>这是app页面</h2>
<div>persinInfo:{JSON.stringify(personInfo)}</div>
<button
onClick={() => {
dispatch(changeName("王五" + Math.random() * 100));
}}
>
修改名称
</button>
<button
onClick={() => {
dispatch(add());
}}
>
修改数字
</button>
<button
onClick={() => {
dispatch(handleAction(Math.random() * 100));
}}
>
异步操作
</button>
</div>
);
};
export default App;