【问题标题】:How to share/split a Redux Store between multiple generic components?如何在多个通用组件之间共享/拆分 Redux Store?
【发布时间】:2020-02-08 20:15:40
【问题描述】:

我有一个名为“VendorResults”的通用组件。我将一个字符串 prop 传递给这些通用组件中的每一个,例如“Microsoft”、“Apple”等。

    <ScrollView>
     <SearchResults/>
     <VendorResults vendor={"microsoft"}/>
     <VendorResults vendor={"oracle"}/>
    </ScrollView>

在这个通用组件中,我将 vendor prop 作为参数传递给我的 Redux-Thunk 操作:

  componentDidMount() {
     const {vendor} = this.props;
     this.props.getVendorInformation(vendor);
  }

API 调用开始,并且调度 Thunk 操作。数据最终会进入 Reducer 并存储。但是,当我有多个通用供应商组件时,无论哪个异步调用最后完成,似乎都优先于所有其他组件。例如,如果 oracle 最后完成加载,则 microsoft 组件的状态将更改并显示 oracle 数据。

操作

  export function getVendorInformation(vendor) {

  const url = `${VENDOR_URL}api/search/${vendor}`;

  return dispatch => {
    dispatch(getVendor());
    fetch(url)
      .then(blob => blob.json())
      .then(data => {
        dispatch(getVendorSuccess(data))
      })
      .catch(e => {
        console.log(e);
        dispatch(getVendorError(e.message))
      });
  };

减速器

export default function(state=initialState, action){
    switch (action.type){
        case FETCHING_VENDOR: return {payload:[], fetching: true}
        case FETCH_VENDOR_SUCCESS: return {payload: action.payload.data}
        case VENDOR_ERROR: return {payload:[], error: true, ...state}
    }
    return state;
}

我的问题:

我想保持这种通用/可重用供应商组件的模式 - 我不希望每个供应商都有一个新组件。动作/减速器也是如此;独特的供应商行动/减少者会变得混乱。

如何将单个 Redux 存储共享/拆分/分区为供应商特定的块,以保持状态分离,但仍然受益于一个流程。谢谢!!

【问题讨论】:

    标签: reactjs react-native redux react-redux state


    【解决方案1】:

    您需要通过操作将供应商传递给减速器,并重新构建您的状态结构。如果供应商列表是预先确定的并且不是很长,那么只创建单独的操作/reducer 可能不会那么混乱。

    否则需要嵌套reducer:

    const supportedActions = [FETCHING_VENDOR, FETCH_VENDOR_SUCCESS, VENDOR_ERROR];
    
    const initialVendorState = {data:[], fetching: false, error: false};
    
    const vendorReducer = (state = initialVendorState, action) => {
        switch (action.type){
            case FETCHING_VENDOR: return {data:[], fetching: true}
            case FETCH_VENDOR_SUCCESS: return {data: action.payload.data}
            case VENDOR_ERROR: return {...state, data:[], error: true}
        }
        return state;
    }
    
    const reducer = (state = {}, action) => {
      if (supportedActions.includes(action.type)) {
        const s = {};
        s[action.payload.vendor] = vendorReducer(state[action.payload.vendor], action);
        return {
          ...state,
          ...s
        };
      }
    
      return state
    }
    
    export default reducer;
    

    你的动作创建者应该把vendor作为参数传递给reducer:

    const fetchVendorSuccess = (vendor, data) => ({
      type: FETCH_VENDOR_SUCCESS,
      payload: {
        vendor,
        data
      }
    });
    

    在您的 connect 函数中,如果 state 没有关于该供应商的任何信息,您将需要使用类似 data: (state[vendor] || {}).data 的 smth 来避免错误

    【讨论】:

      【解决方案2】:

      但是,当我有多个通用供应商组件时,无论哪个异步调用最后完成,似乎都优先于所有其他组件。例如,如果 oracle 最后完成加载,则 microsoft 组件的状态将更改并显示 oracle 数据。

      您看到的是 Oracle 数据,因为在获取供应商数据后,您将使用最新的供应商项目数组覆盖整个供应商状态。

        case FETCH_VENDOR_SUCCESS: return {payload: action.payload.data}
      

      为避免这种情况,您需要将先前的状态与新的状态合并。

      解决方案取决于每个供应商的响应情况。正如 Gennady 建议的那样,您可以使用一个对象并使每个供应商都成为该对象的属性。

      使用平面数组来存储所有不同的供应商项目带来了挑战。您将如何确定供应商是否已被获取?

      为避免覆盖之前的供应商,您需要将新状态与之前的状态合并。例如

        case FETCH_VENDOR_SUCCESS: return [...state.data, ...payload.data]
      

      【讨论】:

        猜你喜欢
        • 2019-12-10
        • 2023-04-01
        • 2019-02-18
        • 2019-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-23
        • 1970-01-01
        相关资源
        最近更新 更多