因此,我尝试使用利用useContext的自定义钩子,当ToastContext更改时,我希望该钩子会重新渲染ToastContainer组件。但是,当上下文更改时,ToastContainer组件不会重新呈现。当使用开发工具时,我可以看到该上下文确实已由该钩子更改,但是未显示新数据。
对不起所有代码,我只是不确定错误在哪里
useToast.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>
</>
)
答案 0 :(得分:1)
几件事:
通过调用toasts.set(id, <Toast {...{ message, color, duration, id }} />)
,您可以直接更改不需要的状态。然后,您使用完全相同的setToasts
对象调用Map
,因为它是相同的引用,所以它不会触发重新渲染。
如果这可行,则通过在呈现的功能组件中调用createToast()
来触发Maximum update depth exceeded
异常,就像这样:
您应该通过单击按钮或其他有意义的操作将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)
}