Skip to content

Latest commit

 

History

History
 
 

9-redux

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

9 - Redux

在本章(应该是目前为止最困难的一章)中,我们将添加 Redux 到我们的应用程序,并将它与 React 结合起来使用。 Redux 负责管理应用程序的状态。它由 storeactionsreducers 组成:store 是一个表示应用程序状态的 JavaScript 对象,actions 表示由用户触发的动作,reducers 表示如何处理这些动作。 reducers 将会改变应用程序的状态(store),当状态被修改时,应用程序可能会发生一些改变。这里有一个很好的 Redux 可视化演示示例。

为了演示如何以最简单的方式使用 Redux,我们的应用程序将包括一个消息和一个按钮。消息的内容是狗是否已经叫了(初始值是没有叫),按钮用于让狗叫,点击按钮后应该更新消息的内容。

需要两个包,reduxreact-redux

  • 运行 yarn add redux react-redux

新建两个文件夹:src/client/actionssrc/client/reducers

  • actions 中新建 dog-actions.js
export const MAKE_BARK = 'MAKE_BARK';

export const makeBark = () => ({
  type: MAKE_BARK,
  payload: true,
});

这里我们定义了一个 action 类型 MAKE_BARK 和一个函数(也称为 action creator),它触发一个名为 makeBarkMAKE_BARK action。两者都使用 export 导出了,因为在其他文件中需要它们。此操作实现了 Flux Standard Action 模型,所以它具有 typepayload 属性。

  • reducers 文件夹中新建 dog-reducer.js
import { MAKE_BARK } from '../actions/dog-actions';

const initialState = {
  hasBarked: false,
};

const dogReducer = (state = initialState, action) => {
  switch (action.type) {
    case MAKE_BARK:
      return { hasBarked: action.payload };
    default:
      return state;
  }
};

export default dogReducer;

这里我们定义了应用程序的初始状态 initialStatedogReducerinitialState 是一个 hasBarked 属性为 false 的 JavaScript 对象,dogReducer 是根据 action 改变 state 的函数。在这个函数中不能直接修改 state,而应该返回一个新的 state。

  • 修改 app.jsx 创建一个 store,替换成以下内容:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import dogReducer from './reducers/dog-reducer';
import BarkMessage from './containers/bark-message';
import BarkButton from './containers/bark-button';

const store = createStore(combineReducers({
  dog: dogReducer,
}));

ReactDOM.render(
  <Provider store={store}>
    <div>
      <BarkMessage />
      <BarkButton />
    </div>
  </Provider>
  , document.querySelector('.app')
);

可以看到,store 是由一个叫 createStore 的函数生成的。通过使用 combineReducers 函数将所有 reducer 结合起来传给 createStore。每个 reducer 都可以重新命名,在这里将其命名为 dog

这是 Redux 的部分。

现在我们将使用 react-redux 将 Redux 和 React 结合起来。为了将我们的 store 传给 React,需要将整个 app 用 <Provider> 组件包裹起来。它只有能有一个子组件,所以我们用一个 <div> 将我们的两个组件 BarkMessageBarkButton 再包了一层。

可以看到,BarkMessageBarkButton 是从 containers 文件夹中导入的。现在我们将介绍 **展示组件 **和 容器组件 的概念。

展示组件笨拙的 React 组件,它们无法知道任何的 Redux 状态。容器组件聪明的 组件,它能获取 Redux 的状态,我们通过使用 connect 方法将这些状态传给 展示组件

译者注:关于容器组件(Smart/Container Components)和展示组件(Dumb/Presentational Components)的可能有不同的名称,可以查看 Redux 中文文档的相关章节

  • 新建两个文件夹 src/client/componentssrc/client/containers
  • components 中新建以下文件:

button.jsx

import React, { PropTypes } from 'react';

const Button = ({ action, actionLabel }) => <button onClick={action}>{actionLabel}</button>;

Button.propTypes = {
  action: PropTypes.func.isRequired,
  actionLabel: PropTypes.string.isRequired,
};

export default Button;

以及 message.jsx:

import React, { PropTypes } from 'react';

const Message = ({ message }) => <div>{message}</div>;

Message.propTypes = {
  message: PropTypes.string.isRequired,
};

export default Message;

这些都是展示组件的例子,他们并没有跟应用程序的 state 关联起来,而是根据传入的 props 来展示内容。button.jsxmessage.jsx 有一点区别,Button 的 props 里有一个 action,绑定在 onClick 事件上。在应用程序的上下文中,Button 标签不会改变(因为它没有绑定任何 state),但是 Message 组件将反映我们的应用程序的状态(绑定了 message 这个 state),并将根据状态而变化。

同样,展示组件不会知道关于 Redux actionsstate 的任何信息,所以我们需要新建一个容器组件动作(actions) 和 数据(data)传给它们。

  • containers 中新建以下文件:

bark-button.js

import { connect } from 'react-redux';
import Button from '../components/button';
import { makeBark } from '../actions/dog-actions';

const mapDispatchToProps = dispatch => ({
  action: () => { dispatch(makeBark()); },
  actionLabel: 'Bark',
});

export default connect(null, mapDispatchToProps)(Button);

以及 bark-message.js:

import { connect } from 'react-redux';
import Message from '../components/message';

const mapStateToProps = state => ({
  message: state.dog.hasBarked ? 'The dog barked' : 'The dog did not bark',
});

export default connect(mapStateToProps)(Message);

BarkButton 中, 我们将 Button 组件和 makeBark 这个 action 以及 Redux 中的 dispatch 方法关联起来,将 BarkMessage 组件和 app 状态中的 Message 关联起来。当状态改变的时候,Message 组件会自动重新渲染(因为它的 props message 改变了)。这些操作都是由 react-redux 中的 connect 方法完成的。

  • 现在可以执行 yarn start ,并打开 index.html 了。可以看到 "The dog did not bark" 的消息以及一个按钮。点击按钮后消息会变成 "The dog barked"。

译者注:本章概念比较多,可能不太容易理解,如果你希望深入地学习 Redux,请查看 Redux 中文文档

下一章:10 - Immutable JS 和 Redux 的改进方法

回到上一章目录