【问题标题】:The function created by useCallback didn't receive latest value of the dependencyuseCallback 创建的函数没有收到依赖的最新值
【发布时间】:2022-01-16 20:03:06
【问题描述】:

我知道这个问题已经被问过很多次了,我也知道useCallback 是如何工作的,但是我的问题与antd UI 框架有关(或者也许没关系)。我做了一个最小的、可重现的例子:

import React, { useState, useCallback } from "react";
import ReactDOM from "react-dom";
import { Form, Input, Button, Table } from "antd";
import faker from "faker";

const mockApi = {
  async getUsers({ country, current, pageSize }) {
    return {
      total: 100,
      users: Array.from({ length: 10 }).map((_) => ({
        id: faker.random.uuid(),
        email: faker.internet.email(),
        country: "US"
      }))
    };
  }
};

const initialPagination = { current: 1, pageSize: 10 };

function App() {
  const [form] = Form.useForm();
  const [pagination, setPagination] = useState(initialPagination);
  const [users, setUsers] = useState([]);
  const [total, setTotal] = useState(0);

  useMemo(() => {
    console.log("render pagination: ", pagination);
  }, [pagination]);

  const getUsers = useCallback(async () => {
    console.log("getUsers pagination: ", pagination);
    const params = {
      ...pagination,
      country: form.getFieldValue("country")
    };
    const getUsersResponse = await mockApi.getUsers(params);
    setUsers(getUsersResponse.users);
    setTotal(getUsersResponse.total);
  }, [pagination]);

  const onPageChanged = useCallback(
    (current) => {
      console.log("change current page to: ", current);
      setPagination({ ...pagination, current });
      getUsers();
    },
    [pagination, getUsers]
  );

  return (
    <div>
      <h1>Test</h1>
      <Form form={form} initialValues={{ email: "" }} onFinish={getUsers}>
        <Form.Item name="country" label="country">
          <Input type="text" />
        </Form.Item>
        <Form.Item>
          <Button htmlType="submit">submit</Button>
        </Form.Item>
      </Form>
      <Table
        pagination={{ ...pagination, onChange: onPageChanged, total }}
        dataSource={users}
        columns={[{ title: "email", dataIndex: "email" }]}
        rowKey="id"
      />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

第 1 步:提交表单

第 2 步:将当前页面更改为 2

第 3 步:将当前页面更改为 3

日志:

render pagination:  {current: 1, pageSize: 10}
getUsers pagination:  {current: 1, pageSize: 10}
change current page to:  2
getUsers pagination:  {current: 1, pageSize: 10}
render pagination:  {current: 2, pageSize: 10}
change current page to:  3
getUsers pagination:  {current: 2, pageSize: 10}
render pagination:  {current: 3, pageSize: 10}

getUsers函数中pagiation.current的值不是最新的值。它始终是以前的值。我使用pagination 作为getUsers 函数的依赖项。所以我认为当onPageChanged事件处理函数被触发时,设置新的分页状态后,getUsers()函数应该用deps的最新值重新创建。

我有点不知道为什么。我知道我可以使用useStatefunctional updates 而不是useCallback + deps。但是我坚持使用useCallback+deps的方式。

Codesandbox

【问题讨论】:

  • getUsers in onPageChanged 将始终是在当前闭包中创建的那个,并且不能通过状态更新来更改。你的问题与这个问题基本相同:stackoverflow.com/questions/54069253/… 这不是 antd 或 react,它是普通的 javascript 闭包。

标签: reactjs react-hooks antd


【解决方案1】:

最好的方法是使用 prevState 获取最后一个值。您应该注意何时触发您的 getUsers(使用 useEffect)的分页更改,working example with useEffect

或者,您也可以将一些参数传递给您的 getUsers 方法:working example with parameter to getUser

【讨论】:

  • 是的。我目前的解决方案是将新的pagination 状态作为getUsers() 的参数传递。实际上,我正在寻找除这种方式之外的解决方案。不过还是谢谢你,给你点赞。
  • 另一种方法是使用useEffect。和第一个例子一样。
猜你喜欢
  • 2021-06-13
  • 2020-04-26
  • 1970-01-01
  • 1970-01-01
  • 2020-04-04
  • 2021-09-29
  • 1970-01-01
  • 1970-01-01
  • 2018-06-06
相关资源
最近更新 更多