簡體   English   中英

Redux:在reducer函數中調用store.getState(),這是一種反模式嗎?

[英]Redux: Calling store.getState() in a reducer function, is that an anti pattern?

我想知道,有時我有一台需要另一台減速機信息的減速機。 例如,我有這個減速器:

import * as ActionTypes from '../actions/action_type_constants';
import KeyCode from 'keycode.js/index';
import {store} from "../index";
import {mod} from "../pure_functions";

export function selectedCompletion(state = 0, action) {
  if (action.type === ActionTypes.arrowKeyPressed) {
    const completionsLength = store.getState().completions.data.length;
    if (action.keyCode === KeyCode.UP) {
      return mod(state - 1, completionsLength);
    } else if (action.keyCode === KeyCode.DOWN) {
      return mod(state + 1, completionsLength);
    }
  }
  return state;
}

我在函數的第二行調用store.getState,否則我無法正確確定索引。

我可以重構這個和另一個減速器,以便它成為一個大的減速器,但為了可讀性,我更喜歡這個選項。

如果我在reducer中使用這種調用store.getState()的模式,我不確定是否會以某種方式解決問題。

是的,這絕對是一種反模式。 減速器功能應該是“純粹的”,並且僅基於它們的直接輸入(當前狀態和動作)。

Redux FAQ在關於reducers之間共享狀態的 FAQ中討論了這類問題。 基本上,您應該編寫一些自定義的reducer邏輯,傳遞所需的其他信息,或將更多信息添加到您的操作中。

我還為Redux文檔編寫了一個名為Structuring Reducers的部分 ,該部分討論了與reducer邏輯相關的一些重要概念。 我鼓勵你仔細閱讀。

您想要的模式是組合的情況,因為您正在准備基於其他域(在reducer域意義上)的其他現有狀態的新狀態。 在Redux文檔中,在題為計算派生狀態的主題下提供了一個示例。

請注意,他們的樣本將容器中的狀態組合在一起 - 而不是在減速器中; 然后喂養需要它的組件。

對於這些來到這個頁面想知道如何將他們的大型應用程序升級到redux 4.0而不改進他們的完整狀態管理,因為getState等在reducers中被禁止:

雖然我和作者一樣,反對這種反模式,當你意識到他們在沒有任何技術原因且沒有選擇退出的情況下禁止使用這些功能時,讓沒有更新的人不幸擁有廣泛使用這個的代碼庫反模式...好吧,我做了一個合並請求,用重型警衛添加一個選擇退出,但它只是立即關閉。

所以我創建了一個redux fork,允許在創建存儲時禁用禁令:

https://www.npmjs.com/package/free-redux

對於其他任何人,請使用此處的示例之一或我在另一個問題中提供的方式:

另一種方法,如果你使用react-redux並且只在一個地方需要這個動作,或者可以創建一個HOC(更高級的組件,真的不需要理解重要的東西,這可能會使你的html膨脹),無論你需要什么該訪問是使用mergeprops與傳遞給操作的其他參數:

const mapState = ({accountDetails: {stateOfResidenceId}}) => stateOfResidenceId;

const mapDispatch = (dispatch) => ({
  pureUpdateProduct: (stateOfResidenceId) => dispatch({ type: types.UPDATE_PRODUCT, payload: stateOfResidenceId })
});

const mergeProps = (stateOfResidenceId, { pureUpdateProduct}) => ({hydratedUpdateProduct: () => pureUpdateProduct(stateOfResidenceId )});

const addHydratedUpdateProduct = connect(mapState, mapDispatch, mergeProps)

export default addHydratedUpdateProduct(ReactComponent);

export const OtherHydratedComponent = addHydratedUpdateProduct(OtherComponent)

當你使用mergeProps返回的東西將被添加到props中時,mapState和mapDispatch將僅用於為mergeProps提供參數。 所以,換句話說,這個函數會將它添加到你的組件props(typescript語法):

{hydratedUpdateProduct: () => void}

(請注意,該函數實際上返回了操作本身而不是void,但在大多數情況下你會忽略它)。

但你能做的是:

const mapState = ({ accountDetails }) => accountDetails;

const mapDispatch = (dispatch) => ({
  pureUpdateProduct: (stateOfResidenceId) => dispatch({ type: types.UPDATE_PRODUCT, payload: stateOfResidenceId })
  otherAction: (param) => dispatch(otherAction(param))
});

const mergeProps = ({ stateOfResidenceId, ...passAlong }, { pureUpdateProduct, ... otherActions}) => ({
  ...passAlong,
  ...otherActions,
  hydratedUpdateProduct: () => pureUpdateProduct(stateOfResidenceId ),
});

const reduxPropsIncludingHydratedAction= connect(mapState, mapDispatch, mergeProps)

export default reduxPropsIncludingHydratedAction(ReactComponent);

這將為道具提供以下內容:

{
  hydratedUpdateProduct: () => void,
  otherAction: (param) => void,
  accountType: string,
  accountNumber: string,
  product: string,
}

總的來說,雖然完全無法解決,但redux維護者表示擴展其軟件包的功能,以便以良好的方式包含這些願望,這將為這些功能創建一個模式,而不支持生態系統的碎片化,令人印象深刻。

像Vuex這樣不那么頑固的軟件包並沒有人們濫用反模式的問題,因為他們迷路了,而支持一種更簡潔的語法,用更少的樣板文件比用everx和最好的支持軟件包存檔更少。 盡管這個包更加通用,但是文檔更容易理解,因為它們不會像reduxs文檔那樣迷失在細節中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM