【问题标题】:Losing router object on child component rerender在子组件重新渲染时丢失路由器对象
【发布时间】:2020-08-09 08:22:35
【问题描述】:

我有一个父组件GoalList 映射到一个子组件:

            {data.goals.map((item, index) => {
                return (
                    <Link
                        href={{ pathname: "/goal", query: { id: item.id } }}
                        key={`goal-item-${index}`}
                    >
                        <a>
                            <li>
                                <div>{item.title}</div>
                            </li>
                        </a>
                    </Link>
                );
            })}

next/router的页面:

import SingleGoal from "../components/SingleGoal";

const Single = () => {
    return <SingleGoal />;
};

export default Single;

子组件:

const SingleGoal = () => {
    const [id, setId] = useState("");
    const router = useRouter();

    useEffect(() => {
        if (router.query.id !== "") setId(router.query.id);
    }, [router]);

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

    if (loading) return <p>Loading...</p>;
    if (error) return `Error! ${error.message}`;

    return (
        <div>
            <h1>{data.goal.title}</h1>
            <p>{data.goal.endDate}</p>
        </div>
    );
};

当我点击父组件中的Link 时,item.id 被正确传输,SINGLE_GOAL_QUERY 正确执行。

但是,当我刷新 SingleGoal 组件时,路由器对象需要一瞬间来填充,并且我收到 GraphQL 警告:

[GraphQL error]: Message: Variable "$id" of required type "ID!" was not provided., Location: [object Object], Path: undefined

在一个类似的项目中,我之前给下一个/路由器的页面组件提供了道具,但这似乎不再起作用:

const Single = (props) => {
    return <SingleGoal id={props.query.id} />;
};

如何解决路由器对象的延迟问题?这是使用 getInitialProps 的情况吗? 感谢您的任何指导。

【问题讨论】:

    标签: javascript reactjs graphql react-hooks


    【解决方案1】:

    在这种情况下,通过page 传输道具的秘诀是通过自定义_app 启用getInitialProps

    之前:

    const MyApp = ({ Component, apollo, pageProps }) => {
        return (
            <ApolloProvider client={apollo}>
                <Page>
                    <Component {...pageProps} />
                </Page>
            </ApolloProvider>
        );
    };
    

    之后:

    const MyApp = ({ Component, apollo, pageProps }) => {
        return (
            <ApolloProvider client={apollo}>
                <Page>
                    <Component {...pageProps} />
                </Page>
            </ApolloProvider>
        );
    };
    
    MyApp.getInitialProps = async ({ Component, ctx }) => {
        let pageProps = {};
    
        if (Component.getInitialProps) {
            // calls page's `getInitialProps` and fills `appProps.pageProps`
            pageProps = await Component.getInitialProps(ctx);
        }
        // exposes the query to the user
        pageProps.query = ctx.query;
        return { pageProps };
    };
    

    现在唯一的缺点是不再生成静态页面,每个请求都使用服务器端渲染。

    【讨论】:

      【解决方案2】:

      您可以通过重新排序挂钩来使用路由器查询 id 设置组件内部的初始状态

      const SingleGoal = () => {
          const router = useRouter();
          const [id, setId] = useState(router.query.id);
      
          useEffect(() => {
              if (router.query.id !== "") setId(router.query.id);
          }, [router]);
      
          const { loading, error, data } = useQuery(SINGLE_GOAL_QUERY, {
              variables: { id: id },
          });
      
          if (loading) return <p>Loading...</p>;
          if (error) return `Error! ${error.message}`;
      
          return (
              <div>
                  <h1>{data.goal.title}</h1>
                  <p>{data.goal.endDate}</p>
              </div>
          );
      };
      

      【讨论】:

      • 这似乎并没有阻止 useQuery 在 id 仍未定义未定义时执行。我收到关于未提供 ID 的相同控制台警告
      猜你喜欢
      • 2021-07-15
      • 2020-02-16
      • 2019-03-02
      • 2019-06-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-04
      • 2018-08-12
      • 2020-01-02
      相关资源
      最近更新 更多