【问题标题】:Update single element of the array in redux state在 redux 状态下更新数组的单个元素
【发布时间】:2022-01-23 01:44:43
【问题描述】:

我有一个包含对象数组的 redux 状态,对于每个对象,我调用一个 api 来获取更多数据

objects.forEach((obj, index) => {
    let newObj = { ...obj };
        service.getMoreData()
            .then(result => {
                newObj.data = result;

                let newObjects =  [...this.props.objectsList] ;

                let index = newObjects.findIndex(el => el.id === newObj.id);
                if (index != -1) {
                    newObjects[index] = newObj;
                    this.props.updateMyState({ objectsList: newObjects });
                }
            })

当我得到两个非常接近的响应时,状态没有正确更新,我丢失了第一个响应的数据。

更新数组的单个元素的正确方法是什么?谢谢!

【问题讨论】:

    标签: arrays reactjs redux


    【解决方案1】:

    因此,由于我不知道 service 是什么,而且这里没有太多内容可做,根据我对您所做的事情的理解,我会这样做:

    那么首先让我们设置一个reducer来处理你要修改的redux状态部分:

    // going to give the reducer a default state
    // array just because I don't know
    // the full use case 
    
    // you have an id in your example so this is the best I can do :(
    const defaultState = [{ id: 123456 }, { id: 123457 }];
    
    const someReducer = (state=defaultState, action) => {
      switch (action.type) {
    
        // this is the main thing we're gonna use
        case 'UPDATE_REDUX_ARRAY':
          return [
            ...action.data
          ]
    
        // return a default state == the state argument
        default:
          return [ 
            ...state 
          ]
      }
    }
    
    export default someReducer;

    接下来你应该为 reducer 设置一些操作,这是可选的,你可以在你的组件中内联,但我个人会这样做:

    // pass data to the reducer using an action
    const updateReduxArray = data => {
      return {
        type: 'UPDATE_REDUX_ARRAY',
        data: data
      }
    }
    
    // export like this because there might
    // be more actions to add later 
    export {
      updateReduxArray
    }

    然后使用react的reducer和action来更新/渲染或任何你想要的

    import { useState } from 'react';
    import { updateReduxArray } from 'path_to_actions_file';
    import { useEffect } from 'react';
    import { axios } from 'axios';
    import { useSelector, useDispatch } from 'react-redux';
    
    const SomeComponent = () => {
    
      // set up redux dispatch
      const dispatch = useDispatch();
    
      // get your redux state
      const reduxArray = useSelector(state => state.reduxArray)  // your gonna have to name this however your's is named
    
      // somewhere to store your objects (state)
      const [arrayOfObjects, updateArrayOfObjects] = useState([]); 
    
      // function to get data from your API
      const getData = async () => {
        // I'm using axios for HTTP requests as its pretty
        // easy to use 
    
        // if you use map you can just return the value of all API calls at once
        const updatedData = await Promise.all(reduxArray.map(async (object, index) => {
          // make the api call
          const response = axios.get(`https://some_api_endpoint/${object.id}`)
            .then(r => r.data)
    
          // return the original object with the addition of the new data
          return {
            ...response,
            ...object
          }
        }))
    
        // once all API calls are done update the state
        // you could just update redux here but this is
        // a clean way of doing it incase you wanna update 
        // the redux state more than once
        // costs more memory to do this though
        updateArrayOfObjects(updatedData)
      }
    
      // basicity the same as component did mount 
      // if you're using classes
      useEffect(() => {
        // get some data from the api
        getData()
      }, [ ])
    
    
      // every time arrayOfObjects is updated
      // also update redux
      useEffect(() => {
        // dispatch your action to the reducer
        dispatch(updateReduxArray(arrayOfObjects))
      }, [arrayOfObjects])
    
    
      // render something to the page??
      return (
        <div>
          { reduxArray.length > 0
            ? reduxArray.map(object => <p>I am { object.id }</p>)
            : <p>nothing to see here</p>
          }
        </div>
      )
    } 
    
    export default SomeComponent;

    您也可以这样做,以便一次只更新 redux 中的一个对象,但即便如此,您最好还是将整个数组传递给 redux,这样我会在组件方面进行数学运算,而不是减速机。

    请注意,在组件中我使用了反应状态和useEffect。您可能不需要这样做,您可以在安装组件时在一个地方处理所有内容,但我们使用的是 React,所以我只是展示了它,以防您想在其他地方使用它:)

    最后我在这里使用react-redux,所以如果你没有设置(你应该这样做),请先离开并做,将你的Provider添加到根组件。这方面有很多指南。

    【讨论】:

    • 我不想立即更新数组,但我想在 API 响应进来时更新数组中的各个项目
    猜你喜欢
    • 2021-12-24
    • 2021-03-15
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    相关资源
    最近更新 更多