最近自己琢磨了一星期,才了解了redux的使用方法。一星期你是在开玩笑吗???
我们学一样东西,必须知道他有什么用,再了解要怎么运用。那redux是用来干什么的呢?
简而言之,redux是用来传递数据的,实现组件间数据共享。类似于vue里面的vuex。
具体使用方法如下:
- 下载redux依赖包
yarn add redux
值得一提的是,redux虽然使用繁琐但可以用于任意项目,vuex只能用于vue项目。
- 引入redux并解构出创建仓库的方法
import {createStore} from 'redux'
createStore是一个函数,有三个参数,默认需要传入第一个参数reducer。
- 创建管理员reducer
//定义一个数据对象defaultState
const defaultState = { num: 1};
//reducer接受两个参数,并返回数据对象
const reducer = (state = defaultState) => {
return state;
};
这里我们把需要共享的数据对象赋值给reducer的第一个形参,并return出去,其实操作数据的时候,需要用到第二个形参,后面会说到。
- 调用createStore方法创建仓库store
//传入必要参数reducer,也就是管理员,才能创建仓库,否则报错
const store = createStore(reducer);
将store在控制台打印后,可以看到她身上有很多方法。
其中,getState()是获取仓库数据;dispatch(action)是修改仓库数据;subscribe(listener)是订阅仓库数据
至此,我们就已经搭建好了一个store的数据仓库,可以实现数据传递了。下面我们来玩玩她。
获取仓库数据
import React, { Component } from "react";
import { createStore } from "redux";
const defaultState = { num: 1 };
const reducer = (state=defaultState)=>{
return state
}
const store = createStore(reducer);
class App extends Component {
// 从仓库中拿到数据对象
state = { ...store.getState()};
render() {
return (
<div>仓库的数据 {this.state.num}
</div>
);
}
}
export default App;
修改仓库数据
只有主组件的情况:
import React, { Component } from "react";
import { createStore } from "redux";
const defaultState = { num: 12 };
const reducer = (state = defaultState, action) => {
// 注意每次获取仓库数据和修改仓库都会触发reducer,不信你可以log一下
console.log("我被触发了", action);
// 根据action处理数据
if (action.type === "hhh") {
state.num++;
return state;
}
return state;
};
const store = createStore(reducer);
class App extends Component {
// 从仓库中拿到数据对象
state = { ...store.getState() };
// 修改仓库数据
addNum = () => {
// 通过dispatch(action)操作仓库
// 注意这里的action是一个对象,且里面必须有一个属性type,否则会报错
const action = {
type: "hhh",
// 其他自定义属性,根据项目需要
name:'小明'
};
store.dispatch(action);
// 这个方法调用完后,会自动执行管理员的函数,就是一开始我们设置的reducer,
// 同时reducer会接收到action对象,这样我们就可以回去reducer写数据修改逻辑了
// 最后要记得更新视图,否则看不到数据变化
this.setState({
num: store.getState().num,
});
};
render() {
return (
<div>
仓库的数据 {this.state.num}{" "}
<button onClick={this.addNum}>我要修改一下</button>
</div>
);
}
}
export default App;
有子组件的情况,定义了一个类子组件Son
import React, { Component } from "react";
import { createStore } from "redux";
const defaultState = { num: 12 };
const reducer = (state = defaultState, action) => {
// 注意每次获取仓库数据和修改仓库都会触发reducer,不信你可以log一下
console.log("我被触发了", action);
// 根据action处理数据
if (action.type === "hhh") {
state.num++;
return state;
}
return state;
};
const store = createStore(reducer);
class Son extends Component {
state = { ...store.getState() };
render() {
return <div>儿子也能获取仓库:{this.state.num}</div>;
}
}
class App extends Component {
// 从仓库中拿到数据对象
state = { ...store.getState() };
// 修改仓库数据
addNum = () => {
// 通过dispatch(action)操作仓库
// 注意这里的action是一个对象,且里面必须有一个属性type,否则会报错
const action = {
type: "hhh",
// 其他自定义属性,根据项目需要
// name:'小明'
};
store.dispatch(action);
// 这个方法调用完后,会自动执行管理员的函数,就是一开始我们设置的reducer,
// 同时reducer会接收到action对象,这样我们就可以回去reducer写数据修改逻辑了
// 最后要记得更新视图,否则看不到数据变化
this.setState({
num: store.getState().num,
});
};
render() {
return (
<div>
仓库的数据 {this.state.num}{" "}
<button onClick={this.addNum}>我要修改一下</button> <br />
<Son></Son>
</div>
);
}
}
export default App;
以上代码运行后出现的结果如下
这是怎么回事呢?
以上的效果不难看出,仓库的数据肯定是改变了,不变的只是子组件Son的视图,要改变视图就必须在子组件写到setState()。那么我们在哪里写呢,这就必须说到仓库的第三个api了。
订阅仓库数据
import React, { Component } from "react";
import { createStore } from "redux";
const defaultState = { num: 12 };
const reducer = (state = defaultState, action) => {
// 注意每次获取仓库数据和修改仓库都会触发reducer,不信你可以log一下
console.log("我被触发了", action);
// 根据action处理数据,处理前要对state进行深拷贝
if (action.type === "hhh") {
// let newState = JSON.parse(JSON.stringify(state));
// newState.num++;
// return newState;
state.num++;
return state;
}
return state;
};
const store = createStore(reducer);
class Son extends Component {
state = { ...store.getState() };
// 我们想要在子组件挂载完毕后,订阅仓库状态
componentDidMount() {
// 要自动更新组件状态,需要执行store的订阅方法subscribe,该方法需要传入一个listener回调函数
// 该方法会在仓库状态改变时自动执行
const listener = () => {
this.setState({
num: store.getState().num,
});
};
store.subscribe(listener);
}
render() {
return <div>儿子也能获取仓库:{this.state.num}</div>;
}
}
class App extends Component {
// 从仓库中拿到数据对象
state = { ...store.getState() };
// 修改仓库数据
addNum = () => {
// 通过dispatch(action)操作仓库
// 注意这里的action是一个对象,且里面必须有一个属性type,否则会报错
const action = {
type: "hhh",
// 其他自定义属性,根据项目需要
// name:'小明'
};
store.dispatch(action);
// 这个方法调用完后,会自动执行管理员的函数,就是一开始我们设置的reducer,
// 同时reducer会接收到action对象,这样我们就可以回去reducer写数据修改逻辑了
// 最后要记得更新视图,否则看不到数据变化
this.setState({
num: store.getState().num,
});
};
render() {
return (
<div>
仓库的数据 {this.state.num}{" "}
<button onClick={this.addNum}>我要修改一下</button> <br />
<Son></Son>
</div>
);
}
}
export default App;
运行结果如下:数据终于同步了
最后说两点小优化,一点是我们在修改数据的时候可以先深拷贝再return,注释部分是深拷贝。
第二点是取消订阅,实际项目我们肯定不止一个子组件,当我们切换到其他子组件时,原先的子组件不会自动取消订阅,需要我们在卸载时取消订阅。
以上就是10分钟上手redux的教程,50行代码不到,超过10分钟你来砍我。如果有不对的地方我先道个歉。
请允许自己写出垃圾,否则你连垃圾都写不出来。