Redux
状态管理器Redux可以方便的组织和管理组件之间的数据。
Redux是一个流行的JavaScript框架,为应用程序提供一个可预测的状态容器。Redux基于简化版本的Flux框架,Flux是Facebook开发的一个框架。在标准的MVC框架中,数据可以在UI组件和存储之间双向流动,而Redux严格限制了数据只能在一个方向上流动。
-
Redux基本原则
- 单一数据源;
- state是只读的;
- 使用纯函数来执行修改;
-
Redux核心API
- createStore(reducer):创建数据仓库需要引入import {createStore} from "redux";
- store.getState():用于获取store里面的数据;
- store.dispatch(action):用于派发action,触发reducer,执行修改动作;
- store.subscribe(componentMethods):订阅store的修改,只要store发生改变,组件中的回调函数就会被执行;
类组件Redux的使用
1.store的创建和使用
1.使用Redux需要安装该模块
npm i redux –save
2.创建reducer文件提供数据源(src/store/reducer.js)
import {createStore} from "redux";
const defaultState = {
name: "框架",
list: ['vue', 'react', 'angular']
}
const reducer = (state=defaultState,action) => {
switch(action.type) {
case "CHANGEUSERNAME":
state.username=action.value
break;
default:
break;
}
state=JSON.parse(JSON.stringify(state))
return state;//必须返回处理后的state,state需要深拷贝
}
const store = createStore(reducer);
export default store;
reducer函数会自己调用一次,state就是使用默认值初始化,之后如果组件中使用dispatch方法就会再次运行reducer函数
2.组件内部获取和使用数据:getState()
//组件内部引入仓库
import store from "./store/reducer.js";
//获取数据
store.getState().username
3.数据的修改和订阅
在组件内部定义要执行的动作action,并触发该动作dispatch。action中type字段是必须的,值通常大写。
// 数据的修改
changeValue() {
const action = {
type: "CHANGEUSERNAME",
value: "测试数据"
}
store.dispatch(action);
}
组件中及时响应更新的数据:订阅。subscribe函数可以监听Redux中state的变化,一旦Redux中的state发生了变化,render函数就会被调用,页面就会被重新渲染
componentDidMount() {
// 订阅store改变事件
// this.sub方法会在reducer函数运行时调用,但是reducer函数第一次自动调用初始化时this.sub方法不会运行
store.subscribe(this.sub.bind(this));
}
sub() {
this.setState(store.getState())
}
仓库中接收动作并修改数据:通过dispatch触发动作后,会将action传递到reducer函数的第二个参数中,第一个参数state就是接受修改前上一次的状态。
const reducer = (state=defaultState,action) => {
switch(action.type) {
case "CHANGEUSERNAME":
state.username=action.value
break;
default:
break;
}
state=JSON.parse(JSON.stringify(state))
return state;//必须返回处理后的state,state需要深拷贝
}
state进行深拷贝的原因是,当通过setState进行重新渲染时会将之前的storeState和现在获取到的newStoreState进行全等判断,如果store中只是修改了引用数据的某个属性,而引用地址没有改变,setState是不会重新渲染页面的。也保证了状态的唯一性。
案例使用
import React, { Component } from 'react'
import store from './store/reducer.js'
export default class App extends Component {
componentDidMount(){
// 获取数据
this.setState({data:store.getState()});
}
render() {
return (
<div>
<h1>App</h1>
<p>{this.state.data.name}</p>
{
this.state.data.list.map((el,index)=>{
return <p key={index}>{el}</p>
})
}
</div>
)
}
}
componentDidMount生命周期函数在render函数后运行,此时this.state.data在render函数中还没有数据,再使用点语法取属性就会报错。
js中问号点 :
this.state?.data.name
作用就是判断这个对象this.state下的data是否为null或者undefined,当是null或者undefined时就直接返回undefined,这样属性取值也不会报错。
import React, { Component } from 'react'
import store from './store/reducer.js'
export default class App extends Component {
componentDidMount(){
// 获取数据
this.setState({data:store.getState()});
}
render() {
return (
<div>
<h1>App</h1>
<p>{this.state?.data.name}</p>
{
this.state?.data.list.map((el,index)=>{
return <p key={index}>{el}</p>
})
}
</div>
)
}
}
import { createStore } from 'redux'
const defaultState = {
name: "框架",
list: ['vue', 'react', 'angular']
};
const reducer = (state = defaultState, action) => {
// 该函数会自己调用一次,state就是使用默认值,之后是组件中使用dispatch方法也会再次调用
console.log(state, action, 666);
switch (action.type) {
case "CHANGENAME":
state.name=action.value;
break;
default:
break;
}
state = JSON.parse(JSON.stringify(state))
return state;//必须返回处理后的state,state需要深拷贝
};
const store = createStore(reducer);
export default store;
import React, { Component } from 'react'
import store from './store/reducer.js'
import First from './First.jsx';
export default class App extends Component {
state={
// 获取数据
data: store.getState()
}
sub(){
this.setState({ data: store.getState() });
}
componentDidMount() {
// 订阅store改变事件,this.sub方法会在reducer函数运行时调用,但是reducer函数第一次自己调用时this.sub方法不会运行
store.subscribe(this.sub.bind(this));
}
change() {
const action = {
type: 'CHANGENAME',
value: '前端主流框架'
}
// store.dispatch方法调用会让仓库中reducer函数运行
store.dispatch(action);
}
render() {
return (
<div>
<h1>App</h1>
<p>{this.state?.data.name}</p>
<button onClick={this.change.bind(this)}>App组件修改仓库的数据</button>
<First></First>
</div>
)
}
}
import React, { Component } from 'react'
import store from './store/reducer.js'
export default class First extends Component {
state = {
// 获取数据
info: store.getState()
}
componentDidMount(){
// 订阅store改变事件
store.subscribe(()=>{
this.setState({ info: store.getState() })
})
}
transmit=()=>{
// 修改store中的数据
store.dispatch({type: 'CHANGENAME',
value: '前端三大主流框架'});
}
render() {
return (
<div>
<h1>First</h1>
<p>{this.state?.info.name}</p>
{
this.state?.info.list.map((el, index) => {
return <p key={index}>{el}</p>
})
}
<button onClick={this.transmit}>First组件修改仓库数据</button>
</div>
)
}
}