【全棧React】第20天: Redux動做

本文轉載自:衆成翻譯
譯者:iOSDevLog
連接:http://www.zcfy.cc/article/3825
原文:https://www.fullstackreact.com/30-days-of-react/day-20/react

使用Redux,咱們來談談咱們如何在咱們的應用中實際修改Redux狀態。redux

昨天, 咱們經歷了整合咱們的反應應用與Redux的困難部分。從如今起, 咱們將使用咱們的Redux設置來定義函數。異步

如今, 咱們的演示應用能顯示當前時間。但目前尚未任何方法能夠更新到新的時間。如今, 讓咱們修改這個。socket

觸發更新

回想一下, 咱們能在Redux中改變數據的惟一方法是經過一個動做建立者。昨天咱們建立了一個Redux的store, 但咱們尚未爲咱們的store創造一個更新的方法。函數

咱們 想要 的是咱們的用戶經過點擊按鈕來更新時間的能力。爲了添加此函數, 咱們須要執行如下幾個步驟:學習

  1. 建立一個 actionCreator 來 分發 咱們store的動做測試

  2. 調用一個元素的 actionCreator "onClick"fetch

  3. 處理歸約器的動做spa

咱們已經實現了第三個步驟, 因此咱們還有兩件事要作, 才能讓這個函數像咱們預期的那樣工做。翻譯

昨天, 咱們討論了什麼是動做, 但不是真正的爲何咱們使用這個東西叫 actionCreators 或他們是什麼。

做爲複習, 動做是一個_必須_ 包含type 值簡單的對象,。咱們建立了一個types.js 文件, 它保存在動做類型常量上, 所以咱們能夠將這些值用做type 屬性。

export const FETCH_NEW_TIME = 'FETCH_NEW_TIME';

做爲快速審閱, 咱們的動做能夠是具備type 鍵的任何對象值。咱們能夠與咱們的行動一塊兒發送數據 (一般, 咱們將把額外的數據做爲一個動做的 payload 有效載荷 來傳遞)。

{
  type: types.FETCH_NEW_TIME,
  payload: new Date().toString()
}

如今, 咱們須要在咱們的store_分發_。咱們能夠這樣作的一個方法就是調用store.dispatch() 函數。

store.dispatch({
  type: types.FETCH_NEW_TIME,
  payload: new Date().toString()
})

然而, 這是至關糟糕的作法。咱們將使用一個函數來返回一個動做, 而不是直接發送該動做, 該函數將 建立 該動做 (所以名稱: actionCreator)。這爲咱們提供了一個更好的測試故事 (易於測試)、可重用性、文檔化和邏輯封裝。

讓咱們在一個名爲redux/actionCreators.js的文件中建立咱們的第一個actionCreator 。咱們將導出所有責任是返回一個適當的動做的一個函數, 以分發咱們的store。

import * as types from './types';

export const fetchNewTime = () => ({
  type: types.FETCH_NEW_TIME,
  payload: new Date().toString(),
})

export const login = (user) => ({
  type: types.LOGIN,
  payload: user
})

export const logout = () => ({
  type: types.LOGOUT,
})

如今, 若是咱們調用這個函數, 什麼都不會發生 , 除了返回一個動做對象。咱們怎樣才能讓這個動做在store裏分發?

It gets called with the dispatch function, so here we can bind the function to call dispatch() on the store.回想一下, 咱們昨天使用了 connect() 函數導出從react-redux?第一個參數稱爲mapStateToProps, 它將狀態映射到一個屬性對象。connect() 函數接受第二個參數, 這使得咱們也能夠將函數映射到屬性。它被調用的dispatch() 函數, 因此在這裏咱們能夠 綁定 函數以便在store調用dispatch()

讓咱們來看看這個動做。在咱們的src/views/Home/Home.js 文件中, 讓咱們經過提供第二個函數來更新咱們的鏈接, 以使用咱們剛剛建立的 actionCreator。咱們將調用mapDispatchToProps這個函數。

import { fetchNewTime } from '../../redux/actionCreators';
  // ...
const mapDispatchToProps = dispatch => ({
  updateTime: () => dispatch(fetchNewTime())
})
  // ...
export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(Home);

如今, updateTime()函數將做爲屬性傳遞, 並將調用dispatch() 當咱們開始行動。讓咱們更新咱們的 <Home />組件, 以便用戶能夠按下一個按鈕來更新時間。

const Home = (props) => {
  return (
    <div className="home">
      <h1>Welcome home!</h1>
      <p>Current time: {props.currentTime}</p>
      <button onClick={props.updateTime}>
        Update time
      </button>
    </div>
  );
}

雖然這個例子並不使人興奮, 但它確實展現了Redux的特色。想象一下, 若是按鈕獲取新的鳴叫或咱們有一個socket驅動更新到咱們的Redux store。這個基本示例演示了Redux的完整功能。

[](#multi-reducers)多歸約器

如今, 咱們咱們的應用有一個單一的歸約器。這是目前的工做, 由於咱們只有少許的簡單數據和 (想必) 只有一我的在這個應用工做。試想一下, 在咱們的應用中爲_每一片數據_開發一個巨大的開關語句。

Ahhhhhhhhhhhhhh...

Redux去營救!Redux有一種方法, 咱們把咱們的Redux歸約器分紅多個歸約器, 每一個都只負責狀態樹的葉子。

咱們能夠從 redux 使用combineReducers() 導出, 以組成一個對象的歸約器函數。對於每一個觸發的動做, 將使用相應的動做調用每一個函數。讓咱們來看看這個動做。

假設咱們 (也許更現實一些) 想跟蹤當前用戶。讓咱們建立一個currentUser Redux模塊..。您猜到了: src/redux/currentUser.js`:

touch src/redux/currentUser.js

咱們將導出咱們從currentTime 模塊導出的相同的四個值...... 固然, 這一次是針對 currentUser 的。咱們在這裏添加了一個基本的結構來處理當前用戶:

import * as types from './types'

export const initialState = {
  user: {},
  loggedIn: false
}

export const reducer = (state = initialState, action) => {
  switch (action.type) {
    case types.LOGIN:
      return {
        ...state, user: action.payload, loggedIn: true};
    case types.LOGOUT:
      return {
        ...state, user: {}, loggedIn: false};
    default:
      return state;
  }
}

讓咱們更新咱們的configureStore() 函數來考慮這些分支, 使用combineReducers 將兩個分支分開

import { createStore, combineReducers } from 'redux';

import { rootReducer, initialState } from './reducers'
import { reducer, initialState as userInitialState } from './currentUser'

export const configureStore = () => {
  const store = createStore(
    combineReducers({
      time: rootReducer,
      user: reducer
    }), // root reducer
    {
      time: initialState, 
      user: userInitialState
    }, // our initialState
  );

  return store;
}

export default configureStore;

如今, 咱們能夠建立login()logout() 動做創造者在咱們的store發送動做。

export const login = (user) => ({
  type: types.LOGIN,
  payload: user
})
  // ...
export const logout = () => ({
  type: types.LOGOUT,
})

如今, 咱們能夠使用 actionCreators 像updateTime() 動做創造者同樣調用loginlogout

哦!這是Redux代碼的又一個沉重的一天。今天, 咱們完成了數據更新和在全局Redux狀態中存儲數據之間的循環。此外, 咱們還學習瞭如何擴展Redux以使用多個歸約器和動做以及多個鏈接的組件。

可是, 咱們尚未對站外數據進行異步調用。明天咱們將進入如何使用中間件與Redux, 這將使咱們可以處理從咱們的應用中獲取遠程數據, 仍然使用Redux的能力來保存咱們的數據。

今天的工做很好, 明天見!

相關文章
相關標籤/搜索