reactjs React查询setQueryData未重新呈现组件

dwbf0jvd  于 2023-02-03  发布在  React
关注(0)|答案(2)|浏览(112)

这个问题我已经处理了一段时间了,但还是解决不了。
我使用React-query作为服务器状态管理库,并尝试在发生变化时使UI状态与服务器状态同步,因为我可以使用变化响应来避免新的API调用,所以我使用了React-query提供的setQueryData特性。
问题是,当一个变异成功时,旧数据被正确地修改了(我可以在React查询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中正确修改了数据。
我知道这是很多代码,问题似乎很复杂,但我真的相信这可能是一件很容易的事情,我没有指出,因为我已经很累了。
谢谢!

uemypmqf

uemypmqf1#

嗯,我修复了它在最坏的可能的方式imho,所以我会回答这个问题,但我真的很想读你的想法。
看起来,只有当变异函数位于我们实际想要重新呈现的组件中时,在预期查询上设置的新查询数据才重新呈现组件。
考虑到这一点,我所做的只是将我的变异函数放在父组件中,并通过子组件传递它。
大概是这样的

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,
          },
        ],
      }
    );
  };
ryhaxcpt

ryhaxcpt2#

你不能变异任何 prop 。
你总是需要创建新版本的对象和 prop ,并使用解构。

    • 示例**
queryClient.setQueryData([QUERY_KEYS.MYKEY], (old) => {

   const myArray = [...old.myArray];

  return {
   ...old,

   // WRONG 
   myArray[0].name: 'text1',

   // CORRECT 
   myArray[0]: {
          ...myArray[0],
           name: 'text1'
   }

}})

相关问题