教程:让我们构建一个由 Redux 驱动的 React 应用

前端之家收集整理的这篇文章主要介绍了教程:让我们构建一个由 Redux 驱动的 React 应用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

在这篇文章,我们将深入探讨 Redux 并了解为什么用它构建一个 React 应用时是很有价值的。我也将带您构建您的第一个 Redux 应用,包括如何使用 Stormpath React SDK 作为 身份认证。之后您可以把这些知识应用到您现有的 React 应用中!@H_301_1@

什么是 Redux?

Redux 是一个帮您在应用中管理 state 的库。它的设计源自 Flux,但是避开了 Flux 编写应用的复杂性。如果您已经编写了一个 Flux 应用,您会很快发现使用 Redux 需要手动编写之前所有的样板。此外与 Flux 不同的是,您有一个单一的 state 容器。这是一个很大的优势,因为它会使 state 共享和代码重用让您构建应用轻松很多。@H_301_1@

Stores

store 仅是一个 state 容器。这是存储 state 并在哪里 actions 被调度及处理的地方。当您开始构建一个 Redux 应用,您要思考如何在应用中存储模块和 state。这很重要因为 Redux 建议只有一个 store,并且由于 state 共享这是之前想到的一个不错的想法。@H_301_1@

Actions

Actions 是表示如何周转我们 state 状态的对象。您可以把 actions 视为 state 树的 API。为了说明,一个添加新用户的 action 可以是:@H_301_1@

{
  type: 'ADD_USER',data: {
    name: 'Foo',email: 'foo@bar.com',password: 'Foobar123_'
  }
}

为了让操作变得更清晰和更容易复用,通常使用一个建造者模式来创建 action 对象。例如在上述情况,您可以为这个对象创建一个函数addUser(name,email,password)。正如您所看到的,actions 本身并不操作任何东西。action 仅仅是一个描述我们如何改变 state 的对象。@H_301_1@

Reducers

Actions 很酷,但它们对自身并没有太大的意义。这就是 reducers 的由来。Reducers 在 store 中通过分发处理 action 来减少这些 actions 对 state 的改变。如果我们在 store 分发一个 action 如 ADD_USER,我们可以用 reducer 将那些添加新用户的 action 入口到 state。@H_301_1@

构建 Redux 应用

现在您了解了基础知识,让我们继续设计和构建第一个由 Redux 驱动的应用。@H_301_1@

为了让操作变的简单,我们构建一个 to-do 应用。这样我们就可以玩转大部分 Redux 中最重要的概念而不是过于关注于应用自身。@H_301_1@

如果我们想到一个 to-do 应用,我们将会需要一些基本的事项。首先一个 to-do 通常由一个列表组成。另外,这个列表包含我们可以更改的待办事项。@H_301_1@

从一个 state 角度来看,我们这个应用的模型类似这样:@H_301_1@

{
  todo: {
    items: [
      {
        message: "Finish Redux blog post...",completed: false
      }
    ]
  }
}

添加 Actions

添加待办事项到 state ?首先,我们希望添加新的待办事项到其中。让我们创建一个 action :@H_301_1@

function addTodo(message) {
  return {
    type: 'ADD_TODO',message: message,completed: false
  };
}

注意这里的 type 字段。这个应该是个唯一的名称用于描述您的 action。通常这个类型是大写格式并用底划线作为单词分隔符。另外您将使用这个名称/标识符在 reducers 中处理具体的 actions 并改变它们的 state 。@H_301_1@

一旦我们增加了新的待办事项,我们肯定希望能够将其标记为已完成,我们也希望能够将其删除,甚至可以清除所有待办事项。@H_301_1@

因此让我们也为这些操作添加 actions :@H_301_1@

function completeTodo(index) {
  return {
    type: 'COMPLETE_TODO',index: index
  };
}

function deleteTodo(index) {
  return {
    type: 'DELETE_TODO',index: index
  };
}

function clearTodo() {
  return {
    type: 'CLEAR_TODO'
  };
}

现在我们已经有了 actions,让我们继续构建 store。如果您还记的刚刚说的,store 是 Redux 应用的核心,关联所有的 state,调度 actions 和 reducers 处理。@H_301_1@

import { createStore } from 'redux';

var defaultState = {
  todo: {
    items: []
  }
};

function todoApp(state,action) {
}

var store = redux.createStore(todoApp,defaultState);

添加 Reducers

现在当我们有一些 actions 和 store,让我们创建第一个 reducer。如果您还记的刚刚说的,reducer 只是一个处理器您可以用它来处理 actions 和改变 state。@H_301_1@

因此我们开始处理 ADD_TODO action 如下所示:@H_301_1@

function todoApp(state,action) {
  switch (action.type) {
    case 'ADD_TODO':
      return Object.assign({},state,{
        items: items.concat([{
          message: action.message,completed: false
        }])
      });

    default:
      return state;
  }
}

注意当我们说一个 reducer “改变” state 时,如果一个 state 需要改变,实际它所做的是创建一个 state 副本并作出改变。如果没有变化,那么返回相同的 state。但在任何情况下您都不应该直接改变 state 因为这样意味着改变 state history 。@H_301_1@

现在当我们有了第一个 action 处理器,让我们为它们增加其余的支持:@H_301_1@

function todoApp(state,{
        todo: {
          items: items.concat([{
            message: action.message,completed: false
          }])
        }
      });

    case 'COMPLETE_TODO':
      var items = [].concat(state.todo.items);

      items[action.index].completed = true;

      return Object.assign({},{
        todo: {
          items: items
        }
      });

    case 'DELETE_TODO':
      var items = [].concat(state.todo.items);

      items.splice(action.index,1);

      return Object.assign({},{
        todo: {
          items: items
        }
      });

    case 'CLEAR_TODO':
      return Object.assign({},{
        todo: {
          items: []
        }
      });

    default:
      return state;
  }
}

把它们结合到一个 React 界面

现在我们已经有了业务逻辑,让我们写一些 UI 代码。由于大部分是常见的 React 知识并且非常类似 Flux 构建的应用,就不再深入讲解。@H_301_1@

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';

var defaultState = {
  todo: {
    items: []
  }
};

// 添加我们在前面步骤中创建的 actions ...

function todoApp(state,action) {
  // 添加我们在前面步骤中的 reducer 逻辑...
}

var store = redux.createStore(todoApp,defaultState);

class AddTodoForm extends React.Component {
  state = {
    message: ''
  };

  onFormSubmit(e) {
    e.preventDefault();
    store.dispatch(addTodo(this.state.message));
    this.setState({ message: '' });
  }

  onMessageChanged(e) {
    var message = e.value.trim();
    this.setState({ message: message });
  }

  render() {
    return (
      <form onSubmit={this.onFormSubmit.bind(this)}>
        <input type="text" placeholder="Todo..." onChange={this.onMessageChanged.bind(this)} value={this.state.message} />
        <button type="submit" value="Add" />
      </form>
    );
  }
}

class TodoItem extends React.Component {
  onDeleteClick() {
    store.dispatch(deleteTodo(this.props.index));
  }

  onCompletedClick() {
    store.dispatch(completeTodo(this.props.index));
  }

  render() {
    return (
      <li>
        <a href="#" onClick={this.onDeleteClick.bind(this)}>[x]</a>
        <a href="#" onClick={this.onCompletedClick.bind(this)}>{this.props.message}</a>
      </li>
    );
  }
}

class TodoList extends React.Component {
  state = {
    items: []
  };

  componentWillMount() {
    store.subscribe(() => {
      var state = store.state();
      this.setState({
        items: state.todo.items
      });
    });
  }

  render() {
    var items = [];

    this.state.items.forEach((item,index) => {
      items.push(<TodoItem
        index={index}
        message={item.message}
        completed={item.completed}
      />);
    });

    return (
      <ol>{ items }</ol>
    );
  }
}

ReactDOM.render(
  <div>
    <h1>Todo</h1>
    <AddTodoForm /><hr />
    <TodoList />
  </div>,document.getElementById('app')
);

正如您所看到的,构建 Redux 应用 UI 部分并不难。唯一的区别就是您用 store.subscribe(listener) 来监听 state 改变,然后通过 store.getState() 检索 state。但除此之外,它非常像一个 Flux 构建的应用。@H_301_1@

Redux 支持 Stormpath React SDK

因为有相当多需要增加 Redux 支持 Stormpath React SDK 需求,我们说干就干。如果您希望为 Redux 配置这个 SDK,简单的配置这个 Stormpath React SDK dispatcher 选项并设置 typeredux 指向 store 到您的 Redux store 如下所示:@H_301_1@

function myApp(state,action) {
  return state;
}

ReactStormpath.init({
  dispatcher: {
    type: 'redux',store: createStore(myApp)
  }
});

一旦完成这些您可以拦截并处理一切 Stormpath React SDK 的 actions 调度。例如,您希望用用户数据来丰富 state,然后简单处理这个 USER_SET action 并将用户数据添加到 state。@H_301_1@

function myApp(state,action) {
  switch (action.type) {
    case 'USER_SET':
      return Object.assign({},{
        user: action.data
      });

    default:
      return state;
  }
}

结束语

正如您在这篇文章所看到的,构建一个由 Redux 驱动的应用是非常容易和简单的。这很像构建一个 Flux,只是是概念略有不同并有较少的样板代码编写。@H_301_1@

希望您喜欢这个教程,能够在将来利用它。@H_301_1@

如果遇到任何无法运行或者问题,不妨看下 参考应用。@H_301_1@

延伸阅读

想了解更多关于 React 应用增加身份认证的内容?看看这些教程:@H_301_1@

原文地址:https://stormpath.com/blog/build-a-redux-powered-react-application/@H_301_1@

猜你在找的React相关文章