【个人向】redux初认识

前言

其实这不是自己第一次看到redux吧,只是之前瞧见的时候,感觉不太好理解它想要表达的意思。后来寒假的时候做APP用到了mobX,同样是状态管理,但是我觉得mobX的语法非常容易理解。也是因为用了mobX反过头来瞧瞧redux,就发现有那么一点思路了,不过这篇文章可能有点乱~有的是直接来自官方文档的,如果有不对的地方,欢迎指出。

几个角色

引用自官网的介绍:

redux是JavaScript状态容器,提供可预测化的状态管理。

说简单了就是类似于一个临时的状态记录和管理工具,当页面上发生了一些交互动作会把页面呈现的数据内容进行修改它就要出场了。这其中有几个重要的角色,分别是Store、Action、以及Reducer。

Store

一个Redux应用只有一个store,类似于是我们应用中所有的数据状态集合,也意味着所有的数据都遵循相同的生命周期,好处是方便了调试、撤销/重做、注入客户端等一系列操作。
Redux store保存了根reducer返回的完整state树,新树则是下一个state。state是只读的,监听器里可以调用store.getState()获得当前state。所有订阅 store.subscribe(listener)的监听器都将被调用。
在根文件输出的时候,可以用一个Provider标签包裹,把store加入Provider的属性,可以做到下面使用connect()的组件都能共享store的内容。

创建过程

import { createStore } from 'redux'
import { Provider } from 'react-redux'
import todoApp from './reducers'  //引入根Reducer
let store = createStore(todoApp) //第二个参数可选, 用于设置 state 初始状态。
render(
    (<Provider store={store}>
        <App />
    </Provider>),
    document.getElementById('root')
)

Action

action

故名思意,action为一个动作,描述发生了什么事。官方解释是:数据从应用传到 store 的有效载荷。action本质是一个普通对象,必须要有type属性来标识每一个不同的动作。

{
      type: ADD_TODO,
      text: 'go shopping'
}

以上可以理解为XX的任务列表添加了购物这个活动。
尽量减少在 action 中传递的数据。
一般是通过store.dispatch()将action传到store。

action创建函数

由于action可能会有很多很多个,比如同样是添加一个待办项,但是里面传输的文字并不一样,所以每次都要重新闯进一个新的action。但是使用函数,就不用这么麻烦了,这样的函数就是action创建函数。

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

把 action 创建函数的结果传给 dispatch() 方法即可把数据传向store:


dispatch(addTodo(text))

或创建一个被绑定的action创建函数来自动 dispatch,然后再调用这个函数:

const boundAddTodo = text => dispatch(addTodo(text))

Reducer

Reducers本质是纯函数,用于指定状态的变化如何响应actions并发送到store,所以它接收旧的state和action,根据action的type和其他内容来返回新的state。根Reducer(也就是总的)可以被划分为很多个小的reducer来对应不同的处理。

function todoApp(state = initialState, action) {
      case(action.type){
          //处理省略,最后返回新的state
      } 
}

注意:

  • 因为传入参数state不能直接更改,所以一般使用复制对象来进行修改操作,如ES6中的Object.assign。
  • 在default的情况下返回原来的state。
  • 要给state一个初始值。

在Reducer内禁止进行以下操作:

  • 修改传入参数;
  • 执行有副作用的操作,如 API 请求和路由跳转;
  • 调用非纯函数,如 Date.now() 或 Math.random()。

根reducer结构可以用combineReducers()拆成多个函数:

 let todoApp = combineReducers({
       todos,
       visibleTodoFilter
 })

以上todos和visibleTodiFilter分别是两个reducer,当触发action后。这个函数会调用这两个reducer,并且把两个结果并成一个state树。

with React

在React项目中使用Redux,有两种组件,分为容器组件和展示组件。容器组件用域数据获取和状态更新,是直接使用Redux,监听Redux的state,同时向Redux派发actions。而展示组件是是从容器组件传来的数据,调用props来获取。在项目开发的时候,最好放在不同的文件夹里来写。

解析ToDoList示例

源码地址:http://www.redux.org.cn/docs/…
index.js

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'   //引入根Reducer
import App from './components/App' //引入主组件

let store = createStore(todoApp)  

render(
  //使用Provider包裹主组件,为了能使用connect共享state
  <Provider store={store}>  
    <App />
  </Provider>,
  document.getElementById('root')
)

actions/index.js

let nextTodoId = 0
//创建于添加待做事项目的action
export const addTodo = text => {
  return {
    type: 'ADD_TODO',
    id: nextTodoId++,
    text
  }
}

//创建过滤筛选动作的action
export const setVisibilityFilter = filter => {
  return {
    type: 'SET_VISIBILITY_FILTER',
    filter
  }
}

//创建完成/取消完成动作相关的action
export const toggleTodo = id => {
  return {
    type: 'TOGGLE_TODO',
    id
  }
}

reducers/todos.js
与待办事列表处理相关的reducer:

const todos = (state = [], action) => {
  switch (action.type) {
    //如果是添加待办事,则与原有待办项目合并
    case 'ADD_TODO':
      return [
        ...state,
        {
          id: action.id,
          text: action.text,
          completed: false
        }
      ]
     //若是完成/取消完成某事,则创建副本进行状态修改
    case 'TOGGLE_TODO':
      return state.map(todo =>
        (todo.id === action.id) 
          ? {...todo, completed: !todo.completed}
          : todo
      )
    default:
      return state
  }
}
export default todos

reducers/visibilityFilter.js
与筛选过滤有关的reducer:

const visibilityFilter = (state = 'SHOW_ALL', action) => {
  switch (action.type) {
    //如果是设置筛选,返回action对象的filter属性
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
} 
export default visibilityFilter

reducers/index.js

import { combineReducers } from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'

//根reducer分为todos和visibilityFilter两个子reducer
const todoApp = combineReducers({
  todos,
  visibilityFilter
})
export default todoApp  

containers/VisibleTodoList.js

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
    case 'SHOW_ALL':
    default:
      return todos
  }
}
//只要store改变,mapStateToProps 函数就会被调用。该回调函数返回一个纯对象,会与组件的 props 合并
const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

//如果传递的是一对象,那么每个定义在该对象的函数都将被当作 Redux action creator,对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中dispatch方法会将action creator的返回值作为参数执行。这些属性会被合并到组件的 props 中。
const mapDispatchToProps = dispatch => {
  return {
    onTodoClick: id => {
      dispatch(toggleTodo(id))
    }
  }
}

//连接获取store数据,返回一个新的已与 Redux store 连接的组件类
const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList
    原文作者:MOCHIKO
    原文地址: https://segmentfault.com/a/1190000013963630
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞