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