简体   繁体   中英

How do I fetch data in a React custom hook only once?

I have a custom hook that fetches a local JSON file that many components make use of.

hooks.js

export function useContent(lang) {
    const [content, setContent] = useState(null);

    useEffect(() => {
        const abortController = new AbortController();
        const signal = abortController.signal;

        fetch(`/locale/${lang}.json`, { signal: signal })
            .then((res) => {
                return res.json();
            })
            .then((json) => {
                setContent(json);
            })
            .catch((error) => {
                console.log(error);
            });

        return () => {
            abortController.abort();
        };
    }, [lang]);

    return { content };
}

/components/MyComponent/MyComponent.js

import { useContent } from '../../hooks.js';

function MyComponent(props) {
  const { content } = useContent('en');
}

/components/MyOtherComponent/MyOtherComponent.js

import { useContent } from '../../hooks.js';

function MyOtherComponent(props) {
  const { content } = useContent('en');
}

My components behave the same, as I send the same en string to my useContent() hook in both. The useEffect() should only run when the lang parameter changes, so seeing as both components use the same en string, the useEffect() should only run once , but it doesn't - it runs multiple times. Why is that? How can I update my hook so it only fetches when the lang parameter changes?

Hooks are run independently in different components (and in different instances of the same component type). So each time you call useContent in a new component, the effect (fetching data) is run once. (Repeated renders of the same component will, as promised by React, not re-fetch the data.) Related: React Custom Hooks fetch data globally and share across components?

A general React way to share state across many components is using a Context hook ( useContext ). More on contexts here . You'd want something like:

const ContentContext = React.createContext(null)

function App(props) {
  const { content } = useContent(props.lang /* 'en' */);
  return (
    <ContentContext.Provider value={content}>
      <MyComponent>
      <MyOtherComponent>
  );
}

function MyComponent(props) {
  const content = useContext(ContentContext);
}

function MyOtherComponent(props) {
  const content = useContext(ContentContext);
}

This way if you want to update the content / language / whatever, you would do that at the app level (or whatever higher level you decide makes sense).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM