安装react-redux, redux,redux-thunk这三个库
1.在src新建redux文件夹
2.在redux文件夹下新建actions和reducers文件夹
3.在actions文件下建立为某组件生成action对象的js文件
4.在reducers文件下建立某组件服务的reducer,同时可以建立index.js用于汇总所有的reducer
5.redux文件夹下新建store.js,引入汇总之后的reducer,汇总的工作在reducers文件下的index.js
6.redux文件夹下新建常量文件constant.js
7.最后在入口文件main.jsx下注册store
另外需要两个钩子:useSelector(), useDispatch()
文件结构如下:
具体代码:
1.src\containers\Count\index.jsx
import React from "react";
import {
increment,
decrement,
incrementAsync,
} from "../../redux/actions/count";
import { useRef } from "react";
import { useSelector, useDispatch } from "react-redux";
export default function Count() {
const count = useSelector((state) => state.count);
const personCount = useSelector((state) => state.persons.length);
const dispatch = useDispatch();
const selectRef = useRef();
const Aincrement = () => {
const { value } = selectRef.current;
dispatch(increment(value * 1));
};
const Adecrement = () => {
const { value } = selectRef.current;
dispatch(decrement(value * 1));
};
const AincrementIfOdd = () => {
const { value } = selectRef.current;
if (count % 2 !== 0) {
dispatch(increment(value * 1));
}
};
const AincrementAsync = () => {
const { value } = selectRef.current;
dispatch(incrementAsync(value * 1, 500));
};
return (
<div>
count组件
<h2>我是Count组件,下方组件总人数为:{personCount}</h2>
<h4>当前求和为:{count}</h4>
<select ref={selectRef}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={Aincrement}>+</button>
<button onClick={Adecrement}>-</button>
<button onClick={AincrementIfOdd}>当前求和为奇数再加</button>
<button onClick={AincrementAsync}>异步加</button>
</div>
);
}
2.src\containers\Person\index.jsx
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { useRef } from "react";
import { addPerson } from "../../redux/actions/person";
export default function Person() {
const count = useSelector((state) => state.count);
const persons = useSelector((state) => state.persons);
const dispatch = useDispatch();
const nameNode = useRef();
const ageNode = useRef();
const AaddPerson = () => {
// 1. 获取输入框的值
const name = nameNode.current.value;
const age = ageNode.current.value;
const personObj = { id: nanoid(), name, age };
// 2. 调用接口
dispatch(addPerson(personObj));
// 3. 清空输入框
nameNode.current.value = "";
ageNode.current.value = "";
};
return (
<div>
<h2>我是Person组件,上方组件求和为{count}</h2>
<input ref={nameNode} type="text" placeholder="输入名字" />
<input ref={ageNode} type="text" placeholder="输入年龄" />
<button onClick={AaddPerson}>添加</button>
<ul>
{persons.map((p) => {
return (
<li key={p.id}>
{p.name}--{p.age}
</li>
);
})}
</ul>
</div>
);
}
3.src\redux\actions\count.js
/*
该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from '../constant'
//同步action,就是指action的值为Object类型的一般对象
export const increment = data => ({type:INCREMENT,data})
export const decrement = data => ({type:DECREMENT,data})
//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const incrementAsync = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(increment(data))
},time)
}
}
4.src\redux\actions\person.js
import {ADD_PERSON} from '../constant'
//创建增加一个人的action动作对象
export const addPerson = personObj => ({type:ADD_PERSON,data:personObj})
5.src\redux\reducers\count.js
/*
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from '../constant'
const initState = 0 //初始化状态
export default function countReducer(preState=initState,action){
// console.log('countReducer@#@#@#');
//从action对象中获取:type、data
const {type,data} = action
//根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return preState + data
case DECREMENT: //若果是减
return preState - data
default:
return preState
}
}
6.src\redux\reducers\person.js
import {ADD_PERSON} from '../constant'
//初始化人的列表
const initState = [{id:'001',name:'tom',age:18}]
export default function personReducer(preState=initState,action){
// console.log('personReducer@#@#@#');
const {type,data} = action
switch (type) {
case ADD_PERSON: //若是添加一个人
//preState.unshift(data) //此处不可以这样写,这样会导致preState被改写了,personReducer就不是纯函数了。
return [data,...preState]
default:
return preState
}
}
7.src\redux\reducers\index.js
/*
该文件用于汇总所有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import {combineReducers} from 'redux'
//引入为Count组件服务的reducer
import count from './count'
//引入为Person组件服务的reducer
import persons from './person'
//汇总所有的reducer变为一个总的reducer
export default combineReducers({
count,
persons
})
8. src\redux\constant.js
/*
该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'
9.src\redux\store.js
import {legacy_createStore, combineReducers,applyMiddleware} from "redux"
//引入汇总之后的reducer,汇总的工作在reducers文件下的index.js
import reducer from "./reducers";
//引入redux-thunk,用于支持异步action
import {thunk} from "redux-thunk";
//暴露store
export default legacy_createStore(
reducer,
applyMiddleware(thunk)
);
10.src\main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import { Provider } from "react-redux";
import store from "./redux/store";
ReactDOM.createRoot(document.getElementById("root")).render(
<Provider store={store}>
<App />
</Provider>
);
11.src\App.jsx
import Person from "./containers/Person";
import Count from "./containers/Count";
function App() {
return (
<div>
<Count></Count>
<hr />
<Person></Person>
</div>
);
}
export default App;