简体   繁体   中英

react hooks avoid re-render and keep required deps

I missed something with useEffect, useCallback and deps.

I have one context and one component. My component load every data I need with fetch() and set a boolean to true in the context to show a spinner. I use the context in another component when I need it.

const LoadingApp = ({children}) => {
    const loadingContext = useContext(LoadingContext);

    const fetchMyData = useCallback(() => {
        loadingContext.setLoading(true);
    }, [loadingContext]);


    useEffect(() => {
        fetchMyData();
    }, [fetchMyData]);

    return (
        <React.Fragment>
            {children}
        </React.Fragment>
    );
};


const LoadingProvider = ({children}) => {
    const [loading, setLoading] = useState(false);

    const setLoading = useCallback((isLoading) => {
        setLoading(loading + (isLoading ? 1: -1));
    }, [setLoading, loading]);

    const isLoading = useCallback(() => {
        return loading > 0;
    }, [loading]);

    return (
        <LoadingContext.Provider value={{setLoading, isLoading}}>
            {children}
        </LoadingContext.Provider>
    )
}

I know I could remove the deps from useEffect or useCallback but it seems to be the wrong way to fix my issue as deps is required.

How could I call a function in a context in a useEffect or useCallback without re-rendering everything?

If you are calling setLoading , then you are always going to trigger a rerender which is what you want.

You could have an empty deps , which means the effect will only run once.

The context always changes when the loading value changes. Change the dependencies of useEffect to only depend on setLoading , which is based on useCallback ( useState setter doesn't change as well), and will stay fixed.

const { setLoading } = useContext(LoadingContext);

const fetchMyData = useCallback(() => {
  setLoading(true);
}, [setLoading]);

You don't actually need the useCallback , since it does the same thing that the original setLoading is doing. You can safely remove this:

const setLoading = useCallback((isLoading) => {
  setLoading(isLoading);
}, [loading]);

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