Redux 在存储中返回一个空数组 - Reducer 无法正常工作?

Posted

技术标签:

【中文标题】Redux 在存储中返回一个空数组 - Reducer 无法正常工作?【英文标题】:Redux returning an empty arrays in store - Reducer not working correctly? 【发布时间】:2021-06-13 22:42:56 【问题描述】:

我最近第一次将 Redux 放入我的应用程序中,并认为它可以正常工作,但它似乎返回了空数组。我检查了我的 Postman 获取帖子,它在后端运行良好。如果数组为空,如下所示,我的商店是否应该返回值?

可能是什么问题?我有一个异步 Thunk 动作创建器和一个我认为可以正常工作的创建切片 Reducer。

如果我的索引 combineReducer 是 createSlice 都显示为白色,这是否意味着它们不能正常工作? auth 和 message 是黄色的,我的登录工作正常,但是我没有为它们使用 createSlice。

更新:我认为这与我的 extraReducers "state: actionpayload.field" 的语法有关。没有错误消息标记,但我不确定它是否在做它应该做的事情。

或者这可能与我的商店有一个 combineReducer 并通过 createSlice 的 reducer 的事实有关吗? (应该是 Redux 工具包的 configureStore)我的身份验证和消息工作正常,但它们不是 Redux。 configureStore 是否同时允许 createSlice 和普通 switch 语句?

index.js

export default combineReducers(

    // combine the reducers
                user,
                fields,
                article,
                diveLog,
                marineList,
                diveSchool,
                diveSpot,
                admin,
                auth,
                message
);

减速器

const fieldsSlice = createSlice(
    name: 'diveLogFields',
    initialState: 
        current: [],
        region: [],
        diveType: [],
        visibility: [],
        diveSpot: [],
    ,
    reducers: ,
    extraReducers: 
        // picks up the success action from the thunk
        [requireFieldData.fulfilled.type]: (state, action) => 
            // set the property based on the field property in the action
            (state: action.payload.field); (state: action.payload.items)
        
    
)
export default fieldsSlice.reducer;

动作

export const requireFieldData = createAsyncThunk(
    'fields/requireData', // action name
    // action expects to be called with the name of the field
    async (fields) => 
        // you need to define a function to fetch the data by field name
        const response = await diveLogFields(fields);
        const  data  = response;
        // what we return will be the action payload
        return 
            fields,
            items: data.data
        ;
    ,
    // only fetch when needed
    
        condition: (fields, getState) => 
            const field = getState();
            // check if there is already data by looking at the array length
            if ( field[fields].length > 0 ) 
                // return false to cancel execution
                return false;
            
        
    
)

更新

当我尝试呈现我的页面时,我仍然收到以下错误消息。我必须进入我的商店并添加 compose Redux 导入。

此消息表明问题出在哪里?

【问题讨论】:

【参考方案1】:

我在您的代码中发现了一些小问题,因此,以下是修复和解释:

切片:

const fieldsSlice = createSlice(
  name: 'diveLogFields',
  initialState: 
    current: [],
    region: [],
    diveType: [],
    visibility: [],
    diveSpot: [],
    fields: [], // Add initial fields array (if you want to store it)
    items: [], // Add initial items array (if you want to store it)
  ,
  reducers: ,
  extraReducers: 
    [requireFieldData.fulfilled.type]: (state, action) => 
      state.fields = action.payload.fields
      state.items = action.payload.items
    ,
  ,
)
export default fieldsSlice.reducer

在上面的代码中,你可以使用state.fields = ...state.items = ...来设置状态数据。看起来我们正在直接改变状态,但我们 不是 因为 ...

Redux Toolkit 允许我们在 reducer 中编写“变异”逻辑。它实际上并没有改变状态,因为它使用 Immer 库,该库检测到“草稿状态”的更改并根据这些更改生成一个全新的不可变状态

AsyncThunkAction:

// Assumption, fake async call
function diveLogFields(fields) 
  return new Promise((resolve) => 
    setTimeout(() => 
      resolve( data:  data: [1, 2, 3] , fields )
    , 2000)
  )


export const requireFieldData = createAsyncThunk(
  'diveLogFields/requireFieldData',
  async (fields) => 
    const response = await diveLogFields(fields)
    const  data  = response
    return 
      fields,
      items: data.data,
    
  ,
  
    condition: (fields,  getState, extra ) => 
      const  fields: fieldsState  = getState() // getState() returns your Redux State
      if (fieldsState.fields.length > 0) 
        return false // cancel the action if fields has some data
      
    ,
  
)

这是一个调度异步操作的示例:

function MyComponent() 
  const dispatch = useDispatch()

  // for example, make async call below hook
  useEffect(() => 
    dispatch(requireFieldData([4, 5, 6]))
  , [dispatch])

  return (
    <>i am MyComponent</>
  )

现在,这是调度操作后状态的样子:

【讨论】:

感谢 Ajeet,所以这与我的 combineReducer 无关,其中包含 createSlice reducer 和 switch 语句的混合?我已经拆分了我的 index.reducers.js 文件,以便我的 auth 和消息减速器位于组合减速器中,并且 configureStore 包含所有 reduxToolkit 减速器。 其实你的问题我并不清楚。但我选择了您的代码并修复了现有问题。 不要将旧的 reducer 样式(使用 switch)与新的样式(使用 Redux Toolkit)混用。旧样式需要编写太多代码。新样式(使用工具包)需要编写更少的代码。但是如果您需要,您可以将旧样式与新样式混合使用。它会起作用的。但我建议采用新风格,检查redux-toolkit.js.org 您当前的代码是否仍有任何问题(按照我在回答中的建议进行更改后)? so this is nothing to do with my combineReducer containing a mix of createSlice reducers and switch statements? 不。它会工作。 (即将旧的 switch 样式与新的 SliceReducer 混合会起作用)。但它可能看起来令人困惑和肮脏。 @Jimbo Redux Toolkit 只是一个轻松创建reducer 和actions 的助手。从createSlice 获得的reducer 是stateaction 的函数,就像任何其他reducer 一样。当它被调用时,它的工作方式与您使用switch 语句创建的reducer 相同。所以把它们结合起来是没有问题的。【参考方案2】:

搞定了。我不得不将我的 store.js 文件更改为以下文件,因为它之前的设置不同。我还使用了我的回复中建议的代码更改。

const store = createStore(
    rootReducer,
    compose(
        applyMiddleware(thunk),
        window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
    )
);

export default store;

【讨论】:

以上是关于Redux 在存储中返回一个空数组 - Reducer 无法正常工作?的主要内容,如果未能解决你的问题,请参考以下文章

react redux Reduc-saga实现 take put takeEvery createSagaMiddleware等

为 React 可重用组件设计 Redux 操作和化简器

combineReducers 破坏 Redux 状态并破坏多个 ImmutableJs 减速器

如何在 redux 存储中保存数组对象数据

Redux:使用 Redux 更新数组的状态

为啥我的数组在附加值后返回 null 或显示一个空数组