【问题标题】:Wait for useQuery before writing to state在写入状态之前等待 useQuery
【发布时间】:2022-11-29 07:20:20
【问题描述】:

我使用 react-query 提取数据,由于稍后要进行一些表单编辑,因此需要将其存储在状态中。

在表单编辑之前,它运行良好:

import { useQuery } from '@apollo/client';
import { SINGLE_PARTICIPANT_QUERY } from 'queries/participantQueries';
import { ProfileGeneral } from './ProfileGeneral';


const ProfilePage = ({ id }) => {

    const {data, loading, error} = useQuery(SINGLE_PARTICIPANT_QUERY, {
        variables: {
            id
        }
    });

    if (loading) {
        return <div>Loading</div>;
    }
    if (error) {
        return (
            <div>
                {error.message} />
            </div>
        );
    }
    const { participant } =data;
    return (
        <div>
           <ProfileGeneral participant={participant} />
        </div>

但是在尝试将它添加到状态之后,我不断收到一条错误消息,表明它在没有准备好数据的情况下呈现。

import { useQuery } from '@apollo/client';
import { SINGLE_PARTICIPANT_QUERY } from 'queries/participantQueries';
import { ProfileGeneral } from './ProfileGeneral';
import { useEffect, useState } from 'react';

const ProfilePage = ({ id }) => {
    const [participant, setParticipant] = useState(null);
    const { data, loading, error } = useQuery(SINGLE_PARTICIPANT_QUERY, {
        variables: {
            id
        }
    });

    useEffect(() => {
        if (data && data.participant) {
            setParticipant(data.participant);
        }
    }, [data, participant]);

    if (loading) {
        return <div>Loading</div>;
    }
    if (error) {
        return (
            <div>
                {error.message} />
            </div>
        );
    }

    return (
        <div>
           <ProfileGeneral participant={participant} />
        </div>

我回来了:

Server Error
TypeError: Cannot read properties of null (reading 'firstName')

This error happened while generating the page. Any console logs will be displayed in the terminal window.

我知道我需要让它等待或在它从查询中获得数据后立即重新呈现,但我不确定如何阻止它。

感谢您的观看!

【问题讨论】:

    标签: reactjs react-hooks react-query


    【解决方案1】:

    这是因为:

    1. setParticipant异步改变状态,
    2. useEffect 在渲染实际发生后调用

      所以即使data.participant不为空,participant也是,直到下一个渲染阶段

      你可以改成这样:

      const ProfilePage = ({ id }) => {
          //...
      
          if (loading || !participant) {
              return <div>Loading</div>;
          }
      
          //...
      }
      

    【讨论】:

      【解决方案2】:

      一个选项是将组件一分为二。一个负责抓取(useQuery),一个负责表单编辑(useState),以便父组件提供初始状态。这种方法的一个缺点是,在加载查询之前,您看不到表单(除非您制作“表单占位符”)。

      例子:

      function Fetcher() {
        const {data, isError, isLoading} = useQuery(...)
      
        if (isLoading) {
          return <Loader />
        }
      
        if (isError) {
          return <p>Oops, failed to load</p>
        }
      
        return <Form initialState={data} />
      }
      
      function Form({ initialState }) {
        const [state, setState] = useState(initialState)
      
        return <form>...</form>
      }
      

      现在,您拥有处于表单状态的数据的本地副本,并且不再有任何异步问题。在您有数据之前,表单根本不会呈现。如果你想要更好的视觉效果,你可以用任何东西替换 Loader!

      如果您需要传播更改(意味着如果查询重新运行并获取新数据),您也可以使用 key 来重置表单。请谨慎使用,因为后台同步会清除表单,即使用户只是在键入内容,因此您需要尝试使用此类查询的选项。

        const {data, isLoading, isError, dataUpdatedAt} = useQuery(...)
       
        ...
      
        return <Form key={dataUpdatedAt} initialState={data} />
      

      【讨论】:

        猜你喜欢
        • 2015-03-31
        • 1970-01-01
        • 1970-01-01
        • 2020-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-20
        • 1970-01-01
        相关资源
        最近更新 更多