从子级设置上下文会导致无限调用循环

问题描述

我有一个使用react-router-dom的应用程序。

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

PlayerPage子组件将SiteContext设置为URL中传递的参数slug的值。

// 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>;
}

问题在于,在加载PlayerPage时,它将调用setValue,它设置上下文的值,并重新加载PlayerPage。这导致无限循环,我的代码崩溃。如何使PlayerPage仅设置一次上下文的值?

解决方法

您的问题在这里:

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>;
}

这将更改上下文状态->重新渲染此组件,这将再次更改状态->重新渲染此组件,等等。

相反,您应该在效果内调用它:

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

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

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