Redux

JavaScript提供的一个可预测性(给一个固定的输入 必定等到一个结果)的状态容器

  • 集中地管理react中多个组件的状态

    redux是一个专门的状态管理库 (在vue中也可以使用 但是在react中会比较多)

  • 需求场景:

    1、某个组建的状态需要共享的时候

    2、一个组件需要改变另一个组件状态的时候

    3、组件中的状态需要在任何地方都可以拿到

  • 三大原则:

    1、单一数据源 整个react中的状态都会被统一管理到store

    2、state是只读的 我们不能直接改变state 而是要通过触发redux中特定的方法进行修改

    3、使用纯函数来执行修改操作:action来改变redux中的state

  • 构建store

    • 在src目录下建立store文件夹包含
      • Store.js
      • Reducer.js
      • Action.js

Store.js(使用redux-devtools中间件)

  • 引入reducer
import {createStore} from "redux";
import reducer from "./reducer"
//第二个参数为使用redux-devtools中间件的操作
export const store = createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION && window.__REDUX_DEVTOOLS_EXTENSION__)

使用多个中间件(compose强函数)

import {createStore , applyMiddleware , compose} from "redux";
import reducer from "./reducer"
import thunk from "redux-thunk";
const composeEnhancers=window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}):compose
const enhancer=composeEnhancers(applyMiddleware(thunk))

export const store = createStore(reducer, enhancer);

Reducer.js

  • 引入方法名
  • 定义默认数据
  • 用于定义各种方法
import {CHANGE_INPUT , ADD_EVENT , SUB_EVENT } from './action'


let obj={
inputValue:'Write Something',
List:[
'早上学习Node',
'下午健身',
'晚上开发项目'
]
}


export default (state=obj,action)=>{
switch (action.type){
case CHANGE_INPUT:{
let newState=JSON.parse(JSON.stringify(state))
newState.inputValue=action.value
return newState
}
case ADD_EVENT:{
let newState=JSON.parse(JSON.stringify(state))
newState.List.push(action.value)
newState.inputValue='Write Something'
return newState
}
case SUB_EVENT:{
let newState=JSON.parse(JSON.stringify(state))
newState.List.splice(action.value,1)
return newState
}
default :return state
}
}

Action.js

  • 引入store
  • export各方法名称(容易找bug)
  • export方法(用于操作store里的变量)触发函数
import {store} from "../redux/store";

export const CHANGE_INPUT='changeInput'
export const ADD_EVENT='addEvent'
export const SUB_EVENT='subEvent'



export function getAction(_type,_value){
const action={
type:_type,
//type为方法名
value:_value
//value为传进来的值
}
//触发
store.dispatch(action)
}

使用redux的组件

  • 引入store
  • 引入各方法名(容易找bug)
  • 引入构建action并触发的函数
  • 组件方法提前绑定this
  • 将store的值放入state对应位置,如果只有store的值则直接赋值给store
  • store订阅并绑定方法重新设置state
import React, {Component} from 'react';
import {Input, Button, List} from "antd";
import {store} from "../redux/store";
import {CHANGE_INPUT , ADD_EVENT , SUB_EVENT , getAction} from '../redux/action'

class Redux1 extends Component {
constructor(props) {
super(props);
this.state = store.getState();
this.changeInputValue = this.changeInputValue.bind(this)
this.storeChange=this.storeChange.bind(this)
store.subscribe(this.storeChange)
this.addEvent=this.addEvent.bind(this)
this.subEvent=this.subEvent.bind(this)
}
render() {
return (
<div>
<h1>Redux</h1>
<div style={{margin: '10px'}}>
<Input
placeholder={this.state.inputValue}
style={{width: '250px'}}
onChange={this.changeInputValue}
value={this.state.inputValue}
/>
<Button type='primary' style={{margin: '0 0 0 10px'}} onClick={this.addEvent}>增加 </Button>
</div>
<div style={{margin: '10px', width: '300px'}}>
<List
bordered
dataSource={this.state.List}
renderItem={(item,index) => (
<List.Item onClick={this.subEvent.bind(this,index)}>
{item}
</List.Item>)}
/>
</div>
</div>
);
}

changeInputValue(e) {
getAction(CHANGE_INPUT,e.target.value)
}
addEvent(){
getAction(ADD_EVENT,this.state.inputValue)
}
subEvent(index){
getAction(SUB_EVENT,index)
}
storeChange(){
this.setState(store.getState())
}
}

export default Redux1;

React-redux

  • 除了以下内容其他和普通Redux一样

  • index.js(入口)

    • 引入Provider并包裹要使用store的组件
    • 引入store并在Provider标签的store属性中传入(提供store的值)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {BrowserRouter} from 'react-router-dom';
import 'antd/dist/antd.css'
import {Provider} from 'react-redux'
import {store} from './redux/store'

ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Provider store={store}>
<App/>
</Provider>
</BrowserRouter>

</React.StrictMode>,
document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

使用react-redux的组件

  • 引入connect
  • 引入方法名
  • 底部export的不是原本的组件而是通过connect链接store后的组件
  • 将store的值映射到props中(connect第一个参数)
  • 将操作store的方法映射到props中(connect第二个参数)
import React, {Component} from 'react';
import {Button, Input, List} from "antd";
import {connect} from 'react-redux'
import {CHANGE_INPUT , ADD_EVENT , SUB_EVENT , getAction} from '../redux/action'

class ReactRedux extends Component {
constructor(props) {
super(props);
}

render() {
return (
<div>
<h1>react-redux</h1>
<div style={{margin: '10px'}}>
<Input
style={{width: '250px'}}
value={this.props.inputValue}
onChange={this.props.inputChange}
/>
<Button type='primary' style={{margin: '0 0 0 10px'}} onClick={this.props.addEvent.bind(this)}>增加</Button>
</div>
<div style={{margin: '10px', width: '300px'}}>
<List
bordered
dataSource={this.props.List}
renderItem={(item,index) => (
<List.Item onClick={this.props.subEvent.bind(this,index)}>
{item}
</List.Item>)}
/>
</div>
</div>
);
}
}


const storeToProps=(store)=>{
return{
inputValue:store.inputValue,
List:store.List
}
}
const dispatchToProps=(dispatch)=>{
return{
inputChange(e){
getAction(CHANGE_INPUT,e.target.value)
},
addEvent(){
getAction(ADD_EVENT,this.props.inputValue)
},
subEvent(index){
getAction(SUB_EVENT,index)
}
}
}

export default connect(storeToProps,dispatchToProps)(ReactRedux);

掘金:前端LeBron

知乎:前端LeBron

持续分享技术博文,关注微信公众号👇🏻

img