2016-02-27 33 views
139

說我有以下幾點:在動作創建器中訪問Redux狀態?

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return { 
    type: SOME_ACTION, 
    } 
} 

而在這一行動的創建者,我要訪問的全局存儲狀態(全減速)。它是更好地做到這一點:

import store from '../store'; 

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return { 
    type: SOME_ACTION, 
    items: store.getState().otherReducer.items, 
    } 
} 

或本:

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return (dispatch, getState) => { 
    const {items} = getState().otherReducer; 

    dispatch(anotherAction(items)); 
    } 
} 

回答

12

當你的場景很簡單,你可以使用

import store from '../store'; 

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return { 
    type: SOME_ACTION, 
    items: store.getState().otherReducer.items, 
    } 
} 

但有時你action creator需要觸發多行動

例如異步請求,所以你需要 REQUEST_LOADREQUEST_LOAD_SUCCESSREQUEST_LOAD_FAIL行動

export const [REQUEST_LOAD, REQUEST_LOAD_SUCCESS, REQUEST_LOAD_FAIL] = [`REQUEST_LOAD` 
    `REQUEST_LOAD_SUCCESS` 
    `REQUEST_LOAD_FAIL` 
] 
export function someAction() { 
    return (dispatch, getState) => { 
     const { 
      items 
     } = getState().otherReducer; 
     dispatch({ 
      type: REQUEST_LOAD, 
      loading: true 
     }); 
     $.ajax('url', { 
      success: (data) => { 
       dispatch({ 
        type: REQUEST_LOAD_SUCCESS, 
        loading: false, 
        data: data 
       }); 
      }, 
      error: (error) => { 
       dispatch({ 
        type: REQUEST_LOAD_FAIL, 
        loading: false, 
        error: error 
       }); 
      } 
     }) 
    } 
} 

注:你需要redux-thunk在行動的創建者返回功能

+1

我可以問一下,是否應該檢查狀態「加載」的狀態,以便在第一個Ajax請求沒有完成的時候進行另一個Ajax請求? – JoeTidee

239

上都安有行動的創作者訪問狀態是否是一個好主意,不同的意見。我認爲可以接受的幾個用例是在您發出請求之前檢查緩存的數據,或者檢查您是否經過身份驗證(換句話說,執行條件分發)。我認爲在動作創建器中傳遞數據(如state.something.items)絕對是一種反模式,因爲它遮蔽了更改歷史記錄而不鼓勵:如果有錯誤並且items不正確,很難跟蹤,其中那些錯誤值來自於它們,因爲它們已經是行動的一部分,而不是由減速器響應行動直接計算出來。所以要小心。 (進一步討論動作創作者訪問狀態的利弊,請參閱博客文章Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability。)

如果您發現需要此操作,那麼您建議的兩種方法都可以。第一種方法不需要任何中間件:

import store from '../store'; 

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return { 
    type: SOME_ACTION, 
    items: store.getState().otherReducer.items, 
    } 
} 

但是你可以看到,它依賴於store是從一些模塊導出一個單例。 我們不建議,因爲它使得它更難add server rendering to your app因爲在大多數情況下在服務器上,你會希望有每個請求一個獨立的專賣店。因此,儘管技術上這種方法有效,但我們不建議從模塊中導出商店。

這就是爲什麼我們推薦第二種方法:

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return (dispatch, getState) => { 
    const {items} = getState().otherReducer; 

    dispatch(anotherAction(items)); 
    } 
} 

這將需要您使用終極版咚中間件,但它工作正常客戶端上和服務器上。你可以閱讀更多關於終極版咚和爲什麼有必要在這種情況下here

理想情況下,你的行爲不應該是「肥」,應包含的信息儘可能少的,但你應該感到自由地做什麼工作最適合你自己的應用程序。 Redux FAQ有關於splitting logic between action creators and reducerstimes when it may be useful to use getState in an action creator的信息。

+4

我有一種情況時,選擇組件中的某些內容可能會觸發PUT或POST,具體取決於商店是否包含與組件相關的數據。將PUT/POST選擇的業務邏輯放在組件中而不是基於thunk的動作創建器是否更好? – vicusbass

+2

這兩個作品,所以取決於你。 –

+1

最佳做法是什麼?我現在正面臨類似的問題,我在我的動作創建者中使用getState。在我的情況下,我使用它來確定如果表單有未決更改(如果是的話,我將分派一個顯示對話框的操作)。 –

1

我想指出,從商店中讀取並不是那麼糟糕 - 根據商店來決定應該做什麼可能更方便,而不是將所有內容都傳遞給組件,然後作爲功​​能的參數。我完全同意Dan的觀點,除非你100%確定你只用於客戶端渲染(否則很難追蹤可能出現的錯誤),否則最好不要將商店用作單人遊戲。

I have created a library最近要處理redux的冗長問題,我認爲將所有內容放入中間件是一個好主意,因此您將everyhing作爲依賴注入。

所以,你的例子看起來像:

import { createSyncTile } from 'redux-tiles'; 

const someTile = createSyncTile({ 
    type: ['some', 'tile'], 
    fn: ({ params, selectors, getState }) => { 
    return { 
     data: params.data, 
     items: selectors.another.tile(getState()) 
    }; 
    }, 
}); 

然而,正如你所看到的,我們並不真的在這裏修改數據,所以是一個很好的機會,我們就可以使用這個選擇其他地方將它結合到別的地方。