子组件重新呈现时丢失路由器对象

时间:2020-04-25 18:44:32

标签: javascript reactjs graphql react-hooks

我有一个父组件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

在一个类似的项目中,我之前曾为next / router的页面组件提供了道具,但这似乎不再起作用:

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

如何解决路由器对象中的延迟?这是使用getInitialProps的情况吗? 谢谢你的指导。

2 个答案:

答案 0 :(得分:0)

您可以通过对钩子重新排序来设置带有路由器查询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>
    );
};

答案 1 :(得分:0)

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

之前:

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 };
};

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