这是我的上下文提供者。子组件将使用
setMyList
来更新 myList
.
// Context Provider
import { createContext, useContext, useState } from 'react';
export let MyContext = createContext();
let initList = ['1']; // initial state
export default function MyProvider({ children }) {
const [myList, setMyList] = useState(initList);
const context = { myList, setMyList };
return (
<MyContext.Provider value={context}>
{children}
</MyContext.Provider>
);
}
我想要做的是在子组件中单击按钮来更新此上下文,然后路由到另一个路径
/another
。但是,由于 useEffect 也在第一次渲染上运行,因此页面会直接跳转到 /another
.
// Child Component
'use client';
import { useRouter } from 'next/navigation';
import { useContext, useEffect, useState } from 'react';
import { MyContext } from '../context-provider';
export default function Child() {
let { myList, setMyList } = useContext(MyContext);
const router = useRouter();
console.log(myList);
useEffect(() => {
// console.log(myList);
router.push('/another');
}, [myList, router]);
return (
<div>
<button type='button' onClick={() => setMyList([...myList, '2'])}>
Update state and Navigate
</button>
</div>
);
}
我能想到的唯一解决方案是将 myList 的当前长度与状态更改之前的先前长度进行比较。还有其他方法可以实现这一目标吗?谢谢!
这里有两种方法可以解决这个问题。
我们让子组件在设置状态时强制导航。 我不喜欢多个孩子监听状态并在状态变化时导航的想法,所以我会从孩子身上完全删除
useEffect
。
// Child Component
'use client';
import { useRouter } from 'next/navigation';
import { useContext } from 'react';
import { MyContext } from '../context-provider';
export default function Child() {
let { setMyList } = useContext(MyContext);
const router = useRouter();
const handleUpdate = ()=>{
setMyList((prev)=> ([...prev, '2']))
router.push("/another")
}
return (
<div>
<button type='button' onClick={handleUpdate}>
Update state and Navigate
</button>
</div>
);
}
如果您确实需要在导航之前监听状态更改,我们可以使父级更具声明性。 我们不仅删除了
useEffect
,还删除了子级的路由,并将其全部提升到父级。
// Context Provider
import { createContext, useEffect, useState } from 'react';
export let MyContext = createContext();
let initList = ['1']; // initial state
export default function MyProvider({ children }) {
const [myList, setMyList] = useState(initList);
const router = useRouter();
useEffect(()=>{
if(myList === initList) return;
router.push("/another")
},[myList, router, initList])
const context = { myList, setMyList };
return (
<MyContext.Provider value={context}>
{children}
</MyContext.Provider>
);
}
还有很多其他方法可以解决这个问题。