2

I have an application that uses react-router-dom.

// App.js
function App() {
    return (
        <SiteContextProvider>
            <Switch>
                <Route path="/player/:slug"><PlayerPage /></Route>
                <Route default><NotFoundPage /></Route>
            </Switch>
        </SiteContextProvider>
        );
}

The PlayerPage child component sets the SiteContext to the value of the parameter slug passed in the URL.

// SiteContextProvider.js
export const SiteContext = React.createContext(null);

export function SiteContextProvider(props) {
    const [value, setValue] = useState(null);

    return <SiteContext.Provider value={{value, setValue}}>{props.children}</SiteContext.Provider>;
}
export function PlayerPage(props) {
    const { slug } = useParams();
    const { value, setValue } = useContext(SiteContext);
    setValue(slug);

    return <span>{value}</span>;
}

The problem is that when PlayerPage loads, it calls setValue, which sets the value of the context, reloading PlayerPage. This causes an infinite loop and my code crashes. How do I make PlayerPage set the value of the context only once?

Amos
  • 333
  • 1
  • 3
  • 12

1 Answers1

3

Your problem is here:

export function PlayerPage(props) {
    const { slug } = useParams();
    const { value, setValue } = useContext(SiteContext);
    // Don't call setValue directly inside the function
    setValue(slug);

    return <span>{value}</span>;
}

This makes the context state change -> rerender this component which will change the state again -> rerender this component etc.

instead you should call it inside an effect:

export function PlayerPage(props) {
    const { slug } = useParams();
    const { value, setValue } = useContext(SiteContext);

    React.useEffect(() => {
        setValue(slug);
    }, [slug, setValue]);

    return <span>{value}</span>;
}
tudor.gergely
  • 4,800
  • 1
  • 16
  • 22