Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to forward data to next page with Apollo and NextJS

I'm working on a web app with NextJS, Apollo and React (hooks).

I have a form that asks the name of the visitor as the first step in a registration process. When submitting the form the name will be saved in the Apollo cache and the visitor gets redirected to the next page.

import React, { useState } from 'react';
import Router , {useRouter}  from 'next/router';
import { useApolloClient } from '@apollo/react-hooks';


const NameForm = props => {
    const [name, setName] = useState("");
    const client = useApolloClient();
    const router = useRouter();

    const handleSubmit = e => {
        e.preventDefault();

        if(!name) return;

        client.writeData({ data: { name } });
        router.push('/user/register');
    }

    return (
        <form onSubmit={handleSubmit}>
            <div>
                <label htmlFor="name">Naam</label>
                <div>
                    <input type="text" id="name" name="name" value={name} onChange={e => setName(e.target.value)} />
                    <button type="submit" onClick={handleSubmit}>Get started</button>
                </div>
            </div>
        </form>
    )
}

export default NameForm;

The next page contains a more extensive form. When visitors come from the homepage, the name is already known and I want to get it back from the cache. I thought

import { gql } from 'apollo-boost';
import { useApolloClient } from '@apollo/react-hooks';
import AddUserForm from '../../components/forms/AddUserForm';

const GET_NAME = gql` 
 query GetName {
    name @client  
}`;

const AddUser = ({ name }) => (
    <React.Fragment>
        <AddUserForm name={name} />
    </React.Fragment>
)

AddUser.getInitialProps = async ctx => {
    const client = useApolloClient();
    const name = await client.cache.readQuery({ query: GET_NAME });

    return { name: name || '' };
}

export default AddUser;

I thought I could do this in the getInititialProps hooks are only allowed in the body of a functional component.

Because of the continuous development of next, react hooks and apollo I'm missing a tutorial/course about this and I find it difficult to find a right way to do this.

I hope someone here can help me further.

like image 630
Thore Avatar asked Mar 29 '20 13:03

Thore


1 Answers

use apollo-client cache can lead you to some questions that really depends on the apollo-client's implementation and nextjs implementation. If you open your app by entering the url to the browser address bar, Next.js will make requests (assuming the view need to fetch data) from server-side, then send to the client the rendered HTML.

Because apollo-client fetch then cache the data from server side, then the question is "Does Next.js send the apollo-client with its cache to client side for next request?"

  • You cannot sure about this unless you understand clearly about Next.js and apollo-client cache (about its implementation or how it works inside, if apollo cache data in-memory on server-side, you will fail if you go this way)

  • The answer is unsure because it depends on two stuffs at the same time. And maybe changed on the future!

So to deal with this problem, just use the Next.js way, it has designed a tunnel for data, it is the query on the url.

const NameForm = props => {
    const [name, setName] = useState("");
    const client = useApolloClient();
    const router = useRouter();

    const handleSubmit = e => {
        e.preventDefault();
        if(!name) return;
        router.push(`/user/register?name=${name}`);
    }
    //render ...
}

import { useRouter } from 'next/router';
import AddUserForm from '../../components/forms/AddUserForm';
const AddUser = () => {
    const router = useRouter();
    return (
        <React.Fragment>
            <AddUserForm name={router.query.name} />
        </React.Fragment>
    )
}
export default AddUser;

If you want to send an object instead of a string?

const data = { name: "FoxeyeRinx", email: "[email protected]" };
const base64 = btoa(JSON.stringify(data));
router.push(`/user/register?data=${base64}`);
const AddUser = () => {
    const router = useRouter();
    const base64 = router.query.data;
    //decode base64 then parse it to js object
    const data = JSON.parse(atob(base64)); 
    return (
        <React.Fragment>
            <AddUserForm data={data}/>
        </React.Fragment>
    )
}

If you think the query is ugly and want to hide the query, use this guide: https://nextjs.org/learn/basics/clean-urls-with-dynamic-routing

like image 186
Foxeye.Rinx Avatar answered Nov 13 '22 00:11

Foxeye.Rinx