最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Next JS: Right way to fetch client-side only data in a Functional Component - Stack Overflow

programmeradmin2浏览0评论

I have a functional ponent. Basically, the page consists of a form - where I need to populate some existing data into the form and let the user update it.

I'm using a hook that I wrote to handle the forms. What it does is this

 const [about, aboutInput] = useInput({
    type: 'textarea',
    name: 'About you',
    placeholder: 'A few words about you',
    initialValue: data && data.currentUser.about,
  })

about is the value and aboutInput is the actual input element itself. I can pass an initialValue to it too.

At the beginning of the ponent I'm fetching the data like so:

const { data, loading, error } = useQuery(GET_CURRENT_USER_QUERY)

This only is executed on the client side and on the server side data is undefined.

Hence this code only works when I navigate to the page through a Link ponent from another client-side page.

It doesn't work for:

  1. When I go the URL directly
  2. When I navigate to this page from another SSR page(which uses getInitailProps)

I don't want to use lifecycle methods/class ponent(since I'm using hooks, and want to keep using the functional ponent.

Is there a nice way to achieve this in Next JS and keep using functional ponent?

I have a functional ponent. Basically, the page consists of a form - where I need to populate some existing data into the form and let the user update it.

I'm using a hook that I wrote to handle the forms. What it does is this

 const [about, aboutInput] = useInput({
    type: 'textarea',
    name: 'About you',
    placeholder: 'A few words about you',
    initialValue: data && data.currentUser.about,
  })

about is the value and aboutInput is the actual input element itself. I can pass an initialValue to it too.

At the beginning of the ponent I'm fetching the data like so:

const { data, loading, error } = useQuery(GET_CURRENT_USER_QUERY)

This only is executed on the client side and on the server side data is undefined.

Hence this code only works when I navigate to the page through a Link ponent from another client-side page.

It doesn't work for:

  1. When I go the URL directly
  2. When I navigate to this page from another SSR page(which uses getInitailProps)

I don't want to use lifecycle methods/class ponent(since I'm using hooks, and want to keep using the functional ponent.

Is there a nice way to achieve this in Next JS and keep using functional ponent?

Share asked Mar 30, 2020 at 14:41 SoorajSooraj 10.6k12 gold badges67 silver badges103 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5

You can fetch client-side only data using the useEffect Hook.

Import it first from react

import { useEffect } from 'react';

Usage in the ponent looks like follows

useEffect(() => {
  return () => {
    // clean-up functions
  }
}, []);

The first argument Is a function and you can make your API calls inside this.

The second argument to the useEffect will determine when the useEffect should be triggered. If you pass an empty array [ ], then the useEffect will only be fired when the ponent Mounts. If you want the useEffect to fire if any props change then pass such props as a dependency to the array.

If you want GET_CURRENT_USER_QUERY from the query string you can pass the argument from the getInitailProps and read this as props in the useEffect array dependency.

I see you mentioned getInitailProps. So you probably know what it does and its caveats. If you want the data to be defined on server side, why not use getInitailProps on the page which the form is in. That way you can retrieve the data from props and pass it to your form ponent. It should work either directly visiting the url or visiting from your other pages.

The question content is slightly confusing, I am not sure why a form is involved, so I'll try to answer based on the title.

The best practices to fetch data client-side are described in the newer version of React documentation. In particular, the "You might not need an effect" page is a precious source of information.

It advocates two things:

  1. use library for client-side data fetching, it's most often not worth it to roll your own solution
  2. if you don't want a library, implement cleaning properly, as demonstrated by the useData hook:
// From React documentation
function useData(url) {
  const [data, setData] = useState(null);
  useEffect(() => {
    let ignore = false;
    fetch(url)
      .then(response => response.json())
      .then(json => {
        if (!ignore) {
          setData(json);
        }
      });
    return () => {
      ignore = true;
    };
  }, [url]);
  return data;
}

Usage:

function SearchResults({ query }) {
  const [page, setPage] = useState(1);
  const params = new URLSearchParams({ query, page });
  const results = useData(`/api/search?${params}`);

  function handleNextPageClick() {
    setPage(page + 1);
  }
  // ...
}

As a bonus, if you want to also display data during the server-render and the first client-render, you can mix server-side data fetching using Next.js built-in features, and use the server data to warn the client-side cache.

For instance in SWR, this is done via the fallback option. I call this pattern "client-server relaying" in my Next.js course, because the server value is passed to the client like a relay. Then the client code handles interactivity: refetching on mutation, polling etc.

发布评论

评论列表(0)

  1. 暂无评论