如何将useState挂钩与异步调用一起使用以更改数组?

时间:2019-10-03 00:16:16

标签: javascript reactjs

我正在尝试从放置请求中更新数组

const [descriptors, setDescriptors] = useState([]);

const handleDescriptorUpdate = (id, descriptorData) => {
    services
      .putDescriptor(id, descriptorData)
      .then((response) => {
        const descriptorIndex = _.findIndex(descriptors, (e) => e.id === id);
        if (descriptorIndex !== -1) {
          const tempDescriptors = [...descriptors];
          tempDescriptors[descriptorIndex] = response.data;
          setDescriptors(tempDescriptors);
        }
      })
      .catch((error) => {
        console.error(error);
      });
  };

当我一次仅执行1个请求时,这很好用,但是当我单击执行两次承诺的更新的按钮时,而不是展开数组并用新的值更新旧值,两者都在传播同一数组,导致在解决第二个承诺时,它使用从服务器 BUT 返回的新值(第二个值)更新状态,从而更改第一个值(被第一个承诺更改的对象)保留其原始值。

描述符最初由对象数组填充(来自get请求):

[
  {
    "id": 24,
    "name": "Test 4.1",
    "percentage": 0,
    "towerId": "5cfc9200-c04a-11e9-89c0-2dd5d3707b1b"
  },
  {
    "id": 23,
    "name": "Test 3.1",
    "percentage": 0,
    "towerId": "5cfc9200-c04a-11e9-89c0-2dd5d3707b1b"
  }
]

2 个答案:

答案 0 :(得分:1)

即使React batches all setStates done during an event handler

setDescriptors在事件处理程序的范围之外 ,因为只有在解决诺言后才调用它。

因此,您需要使用state callback来正确管理描述符版本。

.then((response) => {
  setDescriptors((descriptors) => ( // use state callback
    descriptors.map((desc) =>
      desc.id === id ? { ...desc, ...response.data } : desc
    ) 
  })
}

答案 1 :(得分:0)

我看到您让描述符作为状态而不是引用,正如我在上面的评论中所说,useState不会立即反映更改,因此请在内存中保留数组的一个引用,您可以使用钩子useRef来实现,请参见下一个示例:

const [descriptors, setDescriptors] = useState([]);

const descriptorsReference = useRef(null);

const handleDescriptorUpdate = (id, descriptorData) => {
    services
      .putDescriptor(id, descriptorData)
      .then((response) => {
        const descriptorIndex = _.findIndex(descriptors, (e) => e.id === id);
        if (descriptorIndex !== -1) {
         // Use descriptorsReference instead
          const tempDescriptors = [...descriptorsReference.current];
          tempDescriptors[descriptorIndex] = response.data;
          // Next line is to update the descriptors into descriptors state, this phase doesn't happen immediately 'cause is asynchronous 
          setDescriptors(tempDescriptors);
          // Next line is to update the descriptors in memory, this phase occurs immediately 
          descriptorsReference.current = tempDescriptors
        }
      })
      .catch((error) => {
        console.error(error);
      });
  };
相关问题