redux 笔记(一)

other concepts

  1. SPA(single-page application ,单页面应用)

    单页应用(英语:single-page application,缩写SPA)是一种网络应用程序或网站的模型,它通过动态重写当前页面来与用户交互,而非传统的从服务器重新加载整个新页面。这种方法避免了页面之间切换打断用户体验,使应用程序更像一个桌面应用程序。

Redux

一. 介绍

1. redux产生的原因

随着对JavaScript单页应用程序的要求变得越来越复杂,我们的代码必须比以前更多地处理状态。此状态可以包括服务器响应和缓存数据,以及本地创建的尚未保存到服务器的数据。UI状态的复杂性也在增加,因为我们需要管理活动路线,选定标签,旋钮,分页控件等。

管理这个不断变化的状态是困难的。如果一个模型可以更新另一个模型,那么一个视图可以更新一个模型,该模型会更新另一个模型,而这又可能导致另一个视图更新。在某种程度上,您不再理解您的应用程序会发生什么情况,因为您已经失去了对其状态的何时,为何和如何的控制。当系统不透明且不确定时,很难重现错误或添加新功能。

好像这还不够糟糕,请考虑新的要求在前端产品开发中变得常见。作为开发人员,我们需要处理乐观的更新,服务器端渲染,在执行路由转换之前获取数据等等。我们发现自己试图去处理一个我们以前从来没有处理过的复杂问题,而且我们不可避免地提出这个问题:是放弃的时候了吗?答案是否定的。

这种复杂性很难处理,因为我们正在混合两个对人类头脑非常难以推理的概念:突变和异步性。我把它们叫做曼托斯和可乐。两者在分离方面都很出色,但它们一起造成一团糟。像React这样的库试图通过去除异步和直接DOM操作来解决视图层中的这个问题。但是,管理数据的状态由您决定。这是Redux进入的地方。

在Flux,CQRS和Event Sourcing的步骤之后,Redux试图通过对更新发生的方式和时间施加某些限制来预测状态变化。这些限制反映在Redux 的三个原则中。

2. 核心概念

想象一下,你的应用程序的状态被描述为一个普通的对象。例如,待办事项应用的状态可能如下所示:

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

这个对象就像一个“模型”,除了没有setter。这是因为代码的不同部分不能任意改变状态,导致难以重现的错误。

要改变这个状态,你需要发送一个动作。一个动作是一个普通的JavaScript对象(注意我们如何不引入任何魔法?),它描述了发生的事情。以下是一些示例操作:

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

强制将每一项变更都描述为一项行动,让我们清楚了解应用程序正在发生的事情。如果有什么改变,我们知道它为什么改变。行动就像发生了什么事情的面包屑。最后,为了将状态和动作绑定在一起,我们编写了一个名为reducer的函数。再一次,没有什么神奇的 - 它只是一个以状态和动作为参数的函数,并返回应用程序的下一个状态。为大型应用程序编写这样的功能将很难,因此我们编写管理部分状态的较小函数:

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter
  } else {
    return state
  }
}function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([{ text: action.text, completed: false }])
    case 'TOGGLE_TODO':
      return state.map(
        (todo, index) =>
          action.index === index
            ? { text: todo.text, completed: !todo.completed }
            : todo
      )
    default:
      return state
  }
}

然后我们编写另一个reducer,通过调用这两个reducer来查找相应的状态键来管理我们的应用程序的完整状态:

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  }
}

这基本上是Redux的整个想法。请注意,我们尚未使用任何Redux API。它提供了一些用于简化这种模式的实用程序,但主要想法是描述如何随着时间的推移更新状态以响应操作对象,并且您编写的代码中有90%只是普通的JavaScript,没有使用Redux本身,API或任何魔法。

3. 三个原则

Redux可以用三个基本原则来描述:

①单一的事实来源

该州整个应用程序都存储在一个对象树上的一个内商店。

这使得创建通用应用程序变得很容易,因为您的服务器的状态可以被序列化并融入客户端,而无需额外的编码工作。单个状态树还使调试或检查应用程序变得更加容易; 它还使您能够持续开发您的应用程序状态,从而缩短开发周期。一些传统上难以实现的功能 - 例如撤消/重做 - 如果您的所有状态都存储在单个树中,则可能会突然变得无用。

console.log(store.getState())
​
/* Prints
{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}
*/

②状态是只读的

改变状态的唯一方法是发出一个动作,一个描述发生事件的对象。

这确保了视图和网络回调都不会直接写入状态。相反,他们表达了转变国家的意图。因为所有的变化都是集中的,并且以严格的顺序依次发生,所以没有细微的竞争条件需要注意。由于动作只是普通的对象,因此可以对其进行记录,序列化,存储以及稍后重放以用于调试或测试目的。

store.dispatch({
  type: 'COMPLETE_TODO',
  index: 1
})
​
store.dispatch({
  type: 'SET_VISIBILITY_FILTER',
  filter: 'SHOW_COMPLETED'
})

③使用纯函数 进行更改

要指定状态树如何通过操作进行转换,您需要编写纯粹的reducer。

Reducers只是一个纯函数,它会采用先前的状态和一个动作,并返回下一个状态。记住要返回新的状态对象,而不是改变以前的状态。您可以从一个简化器开始,随着您的应用程序的增长,将其分解成更小的简化器,以管理状态树的特定部分。因为reducer只是函数,所以您可以控制它们的调用顺序,传递其他数据,甚至为常见任务(如分页)创建可重用的reducers。

function visibilityFilter(state = 'SHOW_ALL', action) {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case 'COMPLETE_TODO':
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: true
          })
        }
        return todo
      })
    default:
      return state
  }
}import { combineReducers, createStore } from 'redux'
const reducer = combineReducers({ visibilityFilter, todos })
const store = createStore(reducer)

4. 现有技术

5. 学习资源

6. 生态系统

7. 例子

二. 基础内容

1. Actions

First, let's define some actions.

Actions are payloads of information that send data from your application to your store. They are the only source of information for the store. You send them to the store using store.dispatch().

Here's an example action which represents adding a new todo item:

const ADD_TODO = 'ADD_TODO'
{
  type: ADD_TODO,
  text: 'Build my first Redux app'
}

Actions are plain JavaScript objects. Actions must have a type property that indicates the type of action being performed. Types should typically be defined as string constants. Once your app is large enough, you may want to move them into a separate module.

import { ADD_TODO, REMOVE_TODO } from '../actionTypes'

Note on Boilerplate
You don't have to define action type constants in a separate file, or even to define them at all. For a small project, it might be easier to just use string literals for action types. However, there are some benefits to explicitly declaring constants in larger codebases. Read Reducing Boilerplate for more practical tips on keeping your codebase clean.

Other than type, the structure of an action object is really up to you. If you're interested, check out Flux Standard Action for recommendations on how actions could be constructed.

We'll add one more action type to describe a user ticking off a todo as completed. We refer to a particular todo by index because we store them in an array. In a real app, it is wiser to generate a unique ID every time something new is created.

{
  type: TOGGLE_TODO,
  index: 5
}

It's a good idea to pass as little data in each action as possible. For example, it's better to pass index than the whole todo object.

Finally, we'll add one more action type for changing the currently visible todos.

{
  type: SET_VISIBILITY_FILTER,
  filter: SHOW_COMPLETED
}

Action Creators
Action creators are exactly that—functions that create actions. It's easy to conflate the terms “action” and “action creator”, so do your best to use the proper term.

In Redux, action creators simply return an action:

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

This makes them portable and easy to test.

In traditional Flux, action creators often trigger a dispatch when invoked, like so:

function addTodoWithDispatch(text) {
  const action = {
    type: ADD_TODO,
    text
  }
  dispatch(action)
}

In Redux this is not the case.
Instead, to actually initiate a dispatch, pass the result to the dispatch() function:

dispatch(addTodo(text))
dispatch(completeTodo(index))

Alternatively, you can create a bound action creator that automatically dispatches:

const boundAddTodo = text => dispatch(addTodo(text))
const boundCompleteTodo = index => dispatch(completeTodo(index))

Now you'll be able to call them directly:

boundAddTodo(text)
boundCompleteTodo(index)

The dispatch() function can be accessed directly from the store as store.dispatch(), but more likely you'll access it using a helper like react-redux's connect(). You can use bindActionCreators() to automatically bind many action creators to a dispatch() function.

Action creators can also be asynchronous and have side-effects. You can read about async actions in the advanced tutorial to learn how to handle AJAX responses and compose action creators into async control flow. Don't skip ahead to async actions until you've completed the basics tutorial, as it covers other important concepts that are prerequisite for the advanced tutorial and async actions.

Source Code
actions.js

/*
 * action types
 */export const ADD_TODO = 'ADD_TODO'
export const TOGGLE_TODO = 'TOGGLE_TODO'
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'/*
 * other constants
 */export const VisibilityFilters = {
  SHOW_ALL: 'SHOW_ALL',
  SHOW_COMPLETED: 'SHOW_COMPLETED',
  SHOW_ACTIVE: 'SHOW_ACTIVE'
}/*
 * action creators
 */export function addTodo(text) {
  return { type: ADD_TODO, text }
}export function toggleTodo(index) {
  return { type: TOGGLE_TODO, index }
}export function setVisibilityFilter(filter) {
  return { type: SET_VISIBILITY_FILTER, filter }
}

2. Reducers

3. Store

4. Data Flow (数据流)

5. 与React结合使用

6. 例子

三. 高级内容

1. Async Actions (异步操作)

……

猜你喜欢

转载自www.cnblogs.com/suiyueshentou/p/9148720.html