当我的上下文在子组件内更新时如何导航(router.push())?

问题描述 投票:0回答:1

这是我的上下文提供者。子组件将使用

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 的当前长度与状态更改之前的先前长度进行比较。还有其他方法可以实现这一目标吗?谢谢!

reactjs next.js react-hooks
1个回答
0
投票

这里有两种方法可以解决这个问题。

#1

我们让子组件在设置状态时强制导航。 我不喜欢多个孩子监听状态并在状态变化时导航的想法,所以我会从孩子身上完全删除

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

#2

如果您确实需要在导航之前监听状态更改,我们可以使父级更具声明性。 我们不仅删除了

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

还有很多其他方法可以解决这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.