Redux
Redux是 JavaScript 应用程序的可预测状态容器。
随着项目代码的不断丰富,项目中状态和业务逻辑分散在每个模块里。这让组件的重复使用变得更加困难,也让组件的数量越来越臃肿。Redux 会尝试拆分 程序数据 和 业务逻辑,将它们放在 React 自己的容器中,这样 React 就可以专注于对 视图的管理 了。这让你的软件变得更灵活。
Redux的优缺点:
优缺点并不全面
优势:
1、数据流流动很自然,因为任何 dispatch 都会导致广播,需要依据对象引用是否变化来控制更新粒度。
2、如果充分利用时间回溯的特征,可以增强业务的可预测性与错误定位能力。
缺点:
1、action和reducer太繁琐。一套或者几套action和reducer的组合,看起来很不错,但是一旦功能和需求多了,action和reducer就会很混乱,如果管理不善,都不能愉悦的写代码了。
2、store和state的模棱两可。没有严格的定义哪些存store,哪些存internal state。
3、dispatch是同步的,而且dispatch没办法确认action是否执行成功。
并不是所有情况下 Redux 都是明智的选择,应用 Redux 的场景:
* 你有着相当大量的、随时间变化的数据
* 你的 state 需要有一个单一可靠数据来源
* 你觉得把所有 state 放在最顶层组件中已经无法满足需要了
一、安装
更目录下运行命令安装 redux
npm install --save redux
安装 react-redux
npm install --save react-redux
安装 react-logger
npm install --save redux-logger
二、编辑代码
1、React 项目
代码框架主要延用的是上一节 webpack4+react 配置出来的项目代码。
项目github: https://github.com/Lyh97/wenpack4-react
2、action
Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch()
将 action 传到 store。
(1) 在 src下创建 constants 文件夹,其中创建 actionType.js 文件。
我们约定,action 内必须使用一个 字符串类型 的 type
字段来表示将要执行的动作。多数情况下,type
会被定义成 字符串常量。当应用规模越来越大时,建议使用 单独的模块或文件 来存放 action。因此我们定义一个文件来专门存放 action 的 type常量。
actionType.js
export const HELLO_SET = 'HELLO_SET';
(2) src 下创建 action 文件夹,其中创建 index.js 和 hello.js
Action创建函数 就是生成 action 的方法。“action” 和 “action 创建函数” 这两个概念很容易混在一起,使用时最好注意区分。在 Redux 中的 action创建函数 只是简单的返回一个 action :
hello.js
import * as actionTypes from '../constants/actionTypes'; export function setHello(hello) { return { type: actionTypes.HELLO_SET, hello }; };
index.js
import { setHello } from './hello'; export { setHello };
3、Reducers
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
在 src 下创建 reducers 文件夹,其中创建 hello.js 以及 index.js。
hello.js
import * as actionTypes from '../constants/actionTypes'; const initialState = []; export default function(state = initialState, action) { switch (action.type) { case actionTypes.NAME_SET: return setHello(state, action); } return state; } function setHello(state, action) { const { hello } = action; return [ ...state, ...hello ]; }
index.js
import { combineReducers } from 'redux'; import name from './hello'; export default combineReducers({ hello });
4、Stores
action 来描述“发生了什么”, reducers 来根据 action 更新 state 的用法。
Store 就是把它们联系到一起的对象。强调一下 Redux 应用只有一个单一的 store。
Store 有以下职责:
-
-
- 维持应用的 state;
- 提供
getState()
方法获取 state; - 提供
dispatch(action)
方法更新 state; - 通过
subscribe(listener)
注册监听器; - 通过
subscribe(listener)
返回的函数注销监听器。
-
src 下创建 stores 文件夹,其中创建 configureStore.js
configureStore.js
import { createStore, applyMiddleware } from 'redux'; import rootReducer from '../reducers/index'; import { createLogger } from 'redux-logger'; const logger = createLogger(); const createStoreWithMiddleware = applyMiddleware(logger)(createStore); export default function configureStore(initialState) { return createStoreWithMiddleware(rootReducer, initialState); }
5、组件中的使用
src/index.js也需要编辑:
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import AppTest from './App'; import * as serviceWorker from './serviceWorker'; import configureStore from './stores/configureStore'; import * as actions from './actions'; import { Provider } from 'react-redux'; const hello = 'Hello Word !!'; const store = configureStore(); store.dispatch(actions.setName(hello)); ReactDOM.render( <Provider store={store}> <AppTest /> </Provider>, document.getElementById('root')); serviceWorker.unregister();
我将 redux 用在了我的 App.jsx 组件里 我在其中通过 {this.props.hello} 应用了 redux 中的变量 ,我的 App.jsx 是这么写的。
import React from 'react'; import { connect } from 'react-redux'; class AppTest extends React.Component { constructor(props) { super(props); this.state = { a: 2 } } render() { return ( <div> <p>{this.state.a}</p> {this.props.hello} </div> ) } } function mapStateToProps(state) { return { hello : state.hello } } export default connect(mapStateToProps)(AppTest);