Потеря объекта маршрутизатора при повторном рендеринге дочернего компонента - PullRequest
0 голосов
/ 25 апреля 2020

У меня есть родительский компонент 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 выполняется правильно.

НО, когда я обновляю sh 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 голосов
/ 25 апреля 2020

В этом случае секрет для реквизита, передаваемого через 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 };
};

Единственным недостатком теперь является то, что больше нет генерации страниц stati c, и рендеринг на стороне сервера используется при каждом запросе.

0 голосов
/ 25 апреля 2020

Вы можете установить начальное состояние внутри вашего компонента с помощью идентификатора запроса маршрутизатора, переупорядочив ваши хуки

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