【我的向】redux初認識

前言

其實這不是本身第一次看到redux吧,只是以前瞧見的時候,感受不太好理解它想要表達的意思。後來寒假的時候作APP用到了mobX,一樣是狀態管理,可是我以爲mobX的語法很是容易理解。也是由於用了mobX反過頭來瞧瞧redux,就發現有那麼一點思路了,不過這篇文章可能有點亂~有的是直接來自官方文檔的,若是有不對的地方,歡迎指出。html

幾個角色

引用自官網的介紹:react

redux是JavaScript狀態容器,提供可預測化的狀態管理。

說簡單了就是相似於一個臨時的狀態記錄和管理工具,當頁面上發生了一些交互動做會把頁面呈現的數據內容進行修改它就要出場了。這其中有幾個重要的角色,分別是Store、Action、以及Reducer。redux

Store

一個Redux應用只有一個store,相似因而咱們應用中全部的數據狀態集合,也意味着全部的數據都遵循相同的生命週期,好處是方便了調試、撤銷/重作、注入客戶端等一系列操做。
Redux store保存了根reducer返回的完整state樹,新樹則是下一個state。state是隻讀的,監聽器裏能夠調用store.getState()得到當前state。全部訂閱 store.subscribe(listener)的監聽器都將被調用。
在根文件輸出的時候,能夠用一個Provider標籤包裹,把store加入Provider的屬性,能夠作到下面使用connect()的組件都能共享store的內容。併發

建立過程dom

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屬性來標識每個不一樣的動做。ide

{
      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:spa

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
相關文章
相關標籤/搜索