【问题标题】:React useContext not causing a rerender反应useContext不会导致重新渲染
【发布时间】:2020-07-10 15:31:53
【问题描述】:

所以我正在尝试使用一个自定义钩子,该钩子利用了 useContext,我希望在 ToastContext 更改时重新渲染我的 ToastContainer 组件。但是,当上下文更改时,ToastContainer 组件不会重新呈现。使用开发工具时,我可以看到上下文确实被钩子改变了,但是没有显示新数据。

抱歉所有代码,我只是不确定错误在哪里

使用Toast.js

function useToast () {
  let [toasts, setToasts] = useContext(ToastContext)
  

  function createToast(message, color, duration = 0) {
    let id = Math.floor(Math.random() * 1000)
    toasts.set(id, <Toast {...{ message, color, duration, id }} />)
    setToasts(toasts)

    if (duration) {
      setTimeout(() => { toasts.delete(id); setToasts(toasts)}, duration * 1000)
    }
  }

  return [toasts, createToast]
}

ToastContainer.js

function ToastContainer (props) {
  let [toasts, setToasts] = useContext(ToastContext)
  return( <> {[...toasts.values()]} </>)
}

page.js

function Page (props) {  
    let [toasts, createToast] = useToast()  
    createToast("hello", 'red')
    createToast("world", 'yellow')

    return(<Article />)
}

app.js

function App({Component, pageProps}) {


  const toastState = useState(new Map())

  return (
    <>
          <ToastContext.Provider value={toastState}>
            <ToastContainer/>
            <main>
                <Component {...pageProps}></Component>
            </main>
          </ToastContext.Provider>
    </>
  )

【问题讨论】:

    标签: javascript reactjs react-hooks react-context


    【解决方案1】:

    所以有几件事:

    通过调用toasts.set(id, &lt;Toast {...{ message, color, duration, id }} /&gt;),你直接改变了你不想做的状态。然后,您使用完全相同的 Map 对象调用 setToasts,因此它不会触发重新渲染,因为它是相同的引用。

    另外,如果这有效,通过在您的功能组件中调用createToast() 在它呈现时,您将触发Maximum update depth exceeded 异常,因为它会:

    • 渲染
    • 创建了一个 toast,触发了重新渲染
    • 重新渲染
    • 创建了一个 toast,触发了重新渲染
    • 重新渲染 ...等等

    您应该将 Toast 的创建转变为事件驱动,通过单击按钮或其他有意义的方式。

    您可以使用Map,但您需要执行以下操作:

    const [myMap, setMyMap] = useState(new Map());
    const updateMap = (k,v) => {
      setMyMap(new Map(myMap.set(k,v)));
    }
    

    https://medium.com/swlh/using-es6-map-with-react-state-hooks-800b91eedd5f 所示。这将使用当前 Map 的键值对创建一个新的 Map 对象。

    您也可以使用对象{},并进行一些调整:

    const toastState = useState({});
    
    setToasts({
      ...toasts,
      [id]: <Toast key={id} {...{ message, color, duration, id }} />
    });
    
    function ToastContainer (props) {
      let [toasts, setToasts] = useContext(ToastContext)
      return Object.values(toasts);
    }
    
    if (duration) {
      setTimeout(() => {
        const newToasts = { ...toasts };
        delete newToasts[id];
      }, duration * 1000)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-07
      • 2020-10-19
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 2021-01-17
      • 2015-11-03
      • 1970-01-01
      相关资源
      最近更新 更多