Redux
在上一篇博客里,如果两个子节点要共享数据,就必须把公共数据放到最近公共祖先里,redux的作用就是单独有一块区域可以用来存放公共数据,可以看成全局变量
**redux将所有数据存储到树中,且树是唯一的。**每一个结点都会有一个值
Redux基本概念
store
:存储树结构。state
:维护的数据,一般维护成树的结构。reducer
:对state进行更新的函数,每个state绑定一个reducer。传入两个参数:当前state和action,返回新state。action
:一个普通对象,存储reducer的传入参数,一般描述对state的更新类型。dispatch
:传入一个参数action,对整棵state树操作一遍。
代码示例:(维护一个结点)
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { configureStore } from '@reduxjs/toolkit';
//只有根结点的树 action是一个对象(字典)
//这个type和value是我们传参时自己在字典里定义的 可以任意取
const f1 = (state = 100, action) => {
switch(action.type){
case 'add':
return state + action.value;
case 'sub':
return state - action.value;
default:
return state
}
};
//存储树结构
const store = configureStore({
reducer: f1
});
//在每次dispatch之后输出
store.subscribe(() => {console.log(store.getState())});
//树只有一个参数type 传入add对所有结点操作一遍
store.dispatch({type: "add", value: 1});
store.dispatch({type: "sub", value: 7});
store.dispatch({type: "add", value: 5});
store.dispatch({type: "add", value: 1});
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
</React.StrictMode>
);
代码示例:(维护两个结点)
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { configureStore } from '@reduxjs/toolkit';
import { combineReducers } from '@reduxjs/toolkit';
//第一个结点
const f1 = (state = 100, action) => {
switch(action.type){
case 'add':
return state + action.value;
case 'sub':
return state - action.value;
default:
return state
}
};
//第二个结点
const f2 = (state = "", action) => {
switch(action.type){
case 'concat':
return state + action.character;
default :
return state;
}
}
//父结点 组合f1和f2的方法就是将两个结点作为父结点字典里的对象
const f3 = (state = {}, action) => {
return{
f1: f1(state.f1, action),
f2: f2(state.f2, action),
}
}
// 或者用API实现组合
// const f3 = combineReducers({
// f1; f1,
// f2: f2,
// })
//存储树结构
const store = configureStore({
reducer: f3
});
//在每次dispatch之后输出
store.subscribe(() => {console.log(store.getState())});
//树只有一个参数type 传入add对所有结点操作一遍
store.dispatch({type: "add", value: 1}); //{f1: 101, f2: ""}
store.dispatch({type: "sub", value: 7}); //{f1: 94, f2: ""}
store.dispatch({type: "concat", character: "abc"}); //{f1: 94, f2: "abc"}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
</React.StrictMode>
);
React-Redux基本概念
Provider
组件:用来包裹整个项目,其store属性用来存储redux的store对象。connect(mapStateToProps, mapDispatchToProps)
函数:用来将store与组件关联起来。mapStateToProps
(函数):每次store中的状态更新后调用一次,用来更新组件中的值。mapDispatchToProps
(对象):组件创建时调用一次,用来将store的dispatch函数传入组件。
安装
npm i redux react-redux @reduxjs/toolkit
举例:
App组件下面两个子节点 Number组件(number.jsx)和String组件(string.jsx)
state树包含number和string两个结点,在文件index.js中
首先,如何在Number组件访问number的值,在String组件访问string的值?
用connect
函数:用来将store与组件关联起来。mapStateToProps
app.jsx
import React, { Component } from 'react';
import Number from './number';
import String from './string';
class App extends Component {
state = { }
render() {
return (
<React.Fragment>
<Number />
<String />
</React.Fragment>
);
}
}
export default App;
number.jsx
import React, { Component } from 'react';
import {connect} from 'react-redux';
class Number extends Component {
state = { }
render() {
console.log(this.props);//{number: 100, dispatch: ƒ}
return (
<React.Fragment>
<h1>Number:</h1>
<div>{this.props.number}</div>
</React.Fragment>
);
}
}
//要访问state的number的值,并命名为number
const mapStateToProps = (state, props) => {
return{
number: state.number,
}
}
//将值绑定到组件上 也就是Number的props有了一个参数number
export default connect(mapStateToProps)(Number);
string.jsx
import React, { Component } from 'react';
import { connect, Provider } from 'react-redux';
class String extends Component {
state = { }
render() {
return (
<React.Fragment>
<h1>String</h1>
<div>{this.props.string}</div>
</React.Fragment>
);
}
}
const mapStateToProps = (state, props) => {
return{
string: state.string,
}
};
export default connect(mapStateToProps)(String);
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { configureStore } from '@reduxjs/toolkit';
import { combineReducers } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import App from './components/app';
//第一个结点
const f1 = (state = 100, action) => {
switch(action.type){
case 'add':
return state + action.value;
case 'sub':
return state - action.value;
default:
return state
}
};
//第二个结点
const f2 = (state = ":", action) => {
switch(action.type){
case 'concat':
return state + action.character;
default :
return state;
}
}
//父结点 组合f1和f2的方法就是将两个结点作为父结点字典里的对象
const f3 = (state = {}, action) => {
return{
number: f1(state.f1, action),
string: f2(state.f2, action),
}
}
// 或者用API实现组合
// const f3 = combineReducers({
// f1; f1,
// f2: f2,
// })
//存储树结构
const store = configureStore({
reducer: f3
});
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
其次,如何在Number组件里修改string的值,在String组件里修改number的值?mapDispatchToProps
在Number组件内实现一个按钮“添加”,每次点击添加,在string后面加一个字符y,在String组件内实现两个按钮,sub按钮点击number减2,add按钮点击number加3
number.jsx
import React, { Component } from 'react';
import {connect} from 'react-redux';
class Number extends Component {
state = { }
handleClick = () => {
this.props.concat('y'); //这个concat也就是绑定的concat
}
render() {
return (
<React.Fragment>
<h1>Number:</h1>
<div>{this.props.number}</div>
<button onClick={this.handleClick}>添加</button>
</React.Fragment>
);
}
}
//要访问state的number的值,并命名为number
const mapStateToProps = (state, props) => {
return{
number: state.number,
}
}
const mapDispatchToProps = {
concat :(c) => { //实现将c添加concat到string
return{
type: "concat", //因为string里有这个concat
character: c, //character和type都是string字典里定义的
}
}
};
//将值绑定到组件上 也就是Number的props有了一个参数number
//将concat函数绑定到组件上
export default connect(mapStateToProps, mapDispatchToProps)(Number);
string.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
class String extends Component {
state = { }
handleClickLeft = () =>{
this.props.sub(3);
}
handleClickRight = () =>{
this.props.sub(2);
}
render() {
return (
<React.Fragment>
<h1>String</h1>
<div>{this.props.string}</div>
<button onClick={this.handleClickLeft}>Sub</button>
<button onClick={this.handleClickRight}>Plus</button>
</React.Fragment>
);
}
}
const mapStateToProps = (state, props) => {
return{
string: state.string,
}
};
const mapDispatchToProps = {
sub : (n) => {
return{
type: "sub",
value: n,
}
},
add : (n) => {
return{
typr: "add",
value: n,
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(String);
实现效果:(原谅我不会做动图)
点击添加五次:
点击Sub一次