【问题标题】:React-query setQueryData not re-rendering componentReact-query setQueryData 不重新渲染组件
【发布时间】:2023-02-03 08:25:51
【问题描述】:

我已经处理了一段时间这个问题,但仍然无法解决。

我正在使用 React-query 作为服务器状态管理库,并且我试图在发生突变时使我的 UI 状态与我的服务器状态同步。因为我可以使用突变响应来避免新的 API 调用,所以我使用了 React-query 为我们提供的 setQueryData 功能。

问题是当突变成功时旧数据被正确修改(我可以在 react-query DevTools 中看到它),但是使用它的组件没有被重新渲染,使我的 UI 状态不同步我的服务器状态(好吧,至少用户看不到更新)。

让我展示一些代码,希望有人能给我一些见解。

Component using the query:

const Detail = ({ orderId }) => {
  const { workGroups } = useWorkGroups();
  const navigate = useNavigate();

  const queryClient = useQueryClient();
  const orderQueries = queryClient.getQueryData(["orders"]);
  const queryOrder = orderQueries?.find((ord) => ord.id === orderId);

// more code

Component mutating the query:

const Deliver = ({
  setIsModalOpened,
  artisan,
  index,
  queryQuantity,
  queryOrder,
}) => {
  const [quantity, setQuantity] = useState(() => queryQuantity);

  const { mutate: confirmOrderDelivered } = useMutateOrderDeliveredByArtisan(
    queryOrder.id
  );

  const onSubmit = () => {
    confirmOrderDelivered(
      {
        id: queryOrder.artisan_production_orders[index].id,
        artisan: artisan.user,
        items: [
          {
            quantity_delivered: quantity,
          },
        ],
      },
      {
        onSuccess: setIsModalOpened(false),
      }
    );
  };

// more code

Now the mutation function (ik it's a lot of logic but I dont' want to refetch the data using invalidateQueries since we're dealing with users with a really bad internet connection). Ofc you don't need to understand each step of the fn but what it basically does is update the old queried data. In the beginning I thought it was a mutation reference problem since React using a strict comparison under the hood but I also checked it and It doesn't look like it's the problem. :

{
      onSuccess: (data) => {
        queryClient.setQueryData(["orders"], (oldQueryData) => {
          let oldQueryDataCopy = [...oldQueryData];
          const index = oldQueryDataCopy.findIndex(
            (oldData) => oldData.id === orderId
          );

          let artisanProdOrders =
            oldQueryDataCopy[index].artisan_production_orders;

          let artisanProductionOrderIdx = artisanProdOrders.findIndex(
            (artProdOrd) => artProdOrd.id === data.id
          );

          artisanProdOrders[artisanProductionOrderIdx] = {
            ...artisanProdOrders[artisanProductionOrderIdx],
            items: data.items,
          };

          const totalDelivered = artisanProdOrders.reduce((acc, el) => {
            const delivered = el.items[0].quantity_delivered;
            return acc + delivered;
          }, 0);

          oldQueryDataCopy[index] = {
            ...oldQueryDataCopy[index],
            artisan_production_orders: artisanProdOrders,
            items: [
              {
                ...oldQueryDataCopy[index].items[0],
                quantity_delivered: totalDelivered,
              },
            ],
          };
          return oldQueryDataCopy;
        });
      },

      onError: (err) => {
        throw new Error(err);
      },
    }

最后但并非最不重要的一点是:我已经检查过 oldQueryData 是否被正确修改(控制台登录到突变响应中的 onSuccess fn),并且正如我之前所说,数据在 React-query DevTools 中被正确修改。

我知道这是很多代码,问题似乎很复杂,但我真的相信这可能是一件非常简单的事情,我没有指出,因为我已经很累了。

谢谢!

【问题讨论】:

    标签: javascript reactjs react-query


    【解决方案1】:

    好吧,恕我直言,我以最糟糕的方式修复了它,所以我会回答这个问题,但我真的很想读一读你的想法。

    看起来只有当变异函数位于我们实际想要重新渲染的组件中时,在预期查询上设置的新查询数据才会重新渲染组件。

    考虑到这一点,我所做的只是将我的变异函数放在父组件中,然后将它传递给子组件。

    是这样的:

    const Detail = ({ orderId }) => {
      const { workGroups } = useWorkGroups();
      const navigate = useNavigate();
    
    const { mutate: confirmOrderDelivered } = useMutateOrderDeliveredByArtisan(
        queryOrder.id
      ); ==============> THE MUTATION FN IS NOW IN THE PARENT COMPONENT
    
      const queryClient = useQueryClient();
      const orderQueries = queryClient.getQueryData(["orders"]);
      const queryOrder = orderQueries?.find((ord) => ord.id === orderId);
    
    // more code
    

    First child:

    const Assigned = ({ artisan, queryOrder, index, confirmOrderDelivered }) => {
    
    // THE IMPORTANT PART HERE IS THE PROP BEING PASSED DOWN.
    
     <Modal
              isOpen={isModalOpened}
              toggleModal={setIsModalOpened}
              // className="w312"
              width="80%"
              height="fit-content"
              justifyCont="unset"
              alignItems="unset"
            >
              <Deliver
                setIsModalOpened={setIsModalOpened}
                artisan={artisan}
                queryQuantity={quantity}
                queryOrder={queryOrder}
                index={index}
                confirmOrderDelivered={confirmOrderDelivered} => HERE
              />
            </Modal>
    

    Component that actually needs the mutation fn:

    const Deliver = ({
      setIsModalOpened,
      artisan,
      index,
      queryQuantity,
      queryOrder,
      confirmOrderDelivered,
    }) => {
      const [quantity, setQuantity] = useState(() => queryQuantity);
    
      const onSubmit = () => {
        confirmOrderDelivered( => HERE.
          {
            id: queryOrder.artisan_production_orders[index].id,
            artisan: artisan.user,
            items: [
              {
                quantity_delivered: quantity,
              },
            ],
          }
        );
      };
    

    【讨论】:

    • 我认为问题更多地与您执行更新的方式有关。您确定更新是不可变的吗?也许您可以尝试在结构更简单的codesandbox中重现该问题?
    【解决方案2】:

    你不能改变任何道具。

    您始终需要创建对象和道具的新版本并使用解构。

    例子

    queryClient.setQueryData([QUERY_KEYS.MYKEY], (old) => {
    
       const myArray = [...old.myArray];
    
      return {
       ...old,
    
       // WRONG 
       myArray[index].name: 'text1',
    
       // CORRECT 
       myArray[index]: {
              ...myArray[index],
               name: 'text1'
       }
    
    }})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-28
      • 2022-01-27
      • 1970-01-01
      • 2023-03-13
      • 2021-06-19
      • 2018-04-22
      • 1970-01-01
      相关资源
      最近更新 更多