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';
//redux里面的每一个状态一般值是存到叶节点上,每一个内部节点都是用来关联叶节点的值
//定义一个reducer,这个函数会传入两个值,第一个是上一个state的值,第一次调用的时候会传入一个undefined,我们需要给他一个默认值,可以看成state的一个初始值,
//另外还会传入一个参数action,action是一个对象,里面有一个名字叫type,
const f1=(state=0,action)=>{
switch(action.type){
case 'add':
// return state+1;
// return 可以传参数,例如state不加1了想加一个具体值,由于传入的action是一个对象,所以这里action可以传一个值
return state+action.value;
case 'sub':
// return state-1;
return state-action.value;
default:
return state;
}
};
const f2=(state=":",action)=>{
switch(action.type){
case 'concat':
return state+action.character;
default:
return state;
}
};
// 将两个reducer合并成一个reducer,他初始的话就是一个字典,f3的作用主要是将f1和f2组合起来
//组合两个值的方法就是把子节点f1f2的值作为他的父节点值的字典,对象里面的两个属性
// const f3=(state={},action)=>{
// return{
// f1:f1(state.f1,action),
// f2:f2(state.f2,action),
// }
// };
const f3=combineReducers({
number:f1,
string:f2,
})
//假设当前树里面只有一个节点,我们要把当前节点构建成一个树
//store就是将函数f1构建成一颗状态树,传入一个对象,
const store=configureStore({
// reducer: f1
reducer: f3
});
//订阅函数,可以让我们在每次dispatch执行完之后都可以执行一个函数
// store.subscribe(()=>{console.log(store.getState())});
// //修改这个值,dispatch是传入一个action,action就是一个对象,对象里面只用到了type,所以这个对象里面只有一个值叫type
// //这个函数的意思就是将action这个参数传递给我们整棵树的所有的reducer函数,他会调用整棵树所有的reducer函数
// //当前树里只有一个reducer函数就是f1,所以我们执行这句话的话就会调用一下f1,然后将{type:"add"}传给f1的action
// //调用完之后可以看到action的值是add,所以会执行state+1,那么它会返回state+1,返回的这个值就会作为state的新值
// //这个action其实就是我们传入的这个值
// store.dispatch({type:"add",value:1});
// store.dispatch({type:"add",value:1});
// store.dispatch({type:"add",value:1});
// store.dispatch({type:"sub",value:1});
// store.dispatch({type:"sub",value:1});
// store.dispatch({type:"concat",character:"aaa"});
// store.dispatch({type:"concat",character:"xxx"});
//求整颗树的值
// console.log(store.getState());
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
//如果想在项目里面用到redux的话,就需要用provider将整个项目包含起来
//provider一定要提供一个属性store,这个store就是存我们刚刚创建的store
<Provider store={store}>
<App />
</Provider>
);
app.jsx
import React, { Component } from 'react';
import Number from './number';
import String from './string';
class App extends Component {
state = { }
render() {
return (
// app里有两个组件
<React.Fragment>
<Number />
<hr />
<String/>
</React.Fragment>
);
}
}
export default App;
number.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
class Number extends Component {
state = { }
handleClick=()=>{
this.props.concat('y');
}
render() {
console.log(this.props);
return (
<React.Fragment>
<h3>Number:</h3>
<div>{this.props.number}</div>
<button onClick={this.handleClick}>添加</button>
</React.Fragment>
);
}
}
//在组件里面像是store的值,用connect
//connect返回一个函数,可以将我们自己定义的组件传入进去然后返回一个组装好的组件
//组装的话,可以组装两个东西,第一个是可以将我们的值组装到我们组件的props这个属性里面
//mapStateToProps将我们store里的state这个值绑定到我们组件的props属性上
//传入的第一个函数有两种取值,第一个是state,这个state就是我们store getState之后的结果,也就是我们整个状态树的树结构,状态树的树结构这个值是不包含reducer函数的,值包含state值
//第二个属性是props也就是我们原始的props
const mapStateToProps=(state,props)=>{
// 返回一个字典,返回一个对象,对象里面我们可以定义一下,比如说我们想取出state里面的number这个值,然后我们把number这个值赋到哪个属性上,可以把他赋到number这个属性上
return{
number:state.number,
}
}
//修改
//将dispatch这个函数映射到props里面,只会在创建的时候调用一次
const mapDispatchToProps={
// 在number里面修改string的值 concat是一个函数他最后会返回一个对象,这个对象就是我们dispatch里面用到的action,action就是我们传入的包含type的对象,所以他最后会返回一个对象这个对象里面一定要包含一个action
//在string里添加一个字符,修改string的话,要用到'concat'这个字符串,,concat可以传入一个变量c,c表示我们要添加的字符,要用action的哪个属性这里在传的时候就要用哪个属性
concat:(c)=>{
return {
type:"concat",
character:c,
}
}
}
//将number值绑定到组件上要用到connect函数,connect(mapStateToProps)函数返回值会返回一个函数,函数可以将我们Number这个组件作为输入参数,它会返回一个新的组件,这个新的组件就会将我们state里的number(右边state.number)绑定到我们当前组件的props里面的number(左边number)这个属性上
export default connect(mapStateToProps,mapDispatchToProps)(Number);
string.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
class String extends Component {
state = { }
handleClickAdd=()=>{
this.props.add(10);
}
handleClickSub=()=>{
this.props.sub(1);
}
render() {
console.log(this.props);
return (
<React.Fragment>
<h3>String:</h3>
<div>{this.props.string}</div>
<button onClick={this.handleClickAdd}>加</button>
<button onClick={this.handleClickSub}>减</button>
</React.Fragment>
);
}
}
const mapStateToProps=(state,props)=>{
// 返回一个字典,返回一个对象,对象里面我们可以定义一下,比如说我们想取出state里面的number这个值,然后我们把number这个值赋到哪个属性上,可以把他赋到number这个属性上
return{
string:state.string,
}
}
const mapDispatchToProps={
add:(x)=>{
return {
type:"add",
value:x,
}
},
sub:(x)=>{
return{
type:"sub",
value:x,
}
}
}
//将number值绑定到组件上要用到connect函数,connect(mapStateToProps)函数返回值会返回一个函数,函数可以将我们Number这个组件作为输入参数,它会返回一个新的组件,这个新的组件就会将我们state里的number(右边state.number)绑定到我们当前组件的props里面的number(左边number)这个属性上
export default connect(mapStateToProps,mapDispatchToProps)(String);