我有一个snack bar component
,它会显示一条吐司消息几秒钟,然后消失。我有一个App component
,其中包含一个button
,单击该button
时,我想控制snack bar component
。第一次单击时,snack bar
看起来很好,并在指定的时间结束后消失。但是当我再次单击它时,snack bar
没有出现。我每次都将show state
初始化为true,但snack bar
并未出现。请告诉我我要去哪里错了以及如何纠正这个问题。以下是文件。我正在使用自定义钩子来控制小吃店的外观行为。
App.js
import React, { useState } from "react";
import { Snackbar } from "./Snackbar";
function App() {
const [display, setDisplay] = useState(false);
return (
<div>
<button onClick={() => setDisplay(true)}>Click me</button>
{display && <Snackbar message="hello" />}
</div>
);
}
export default App;
Snackbar.js
import React from "react";
import { useSnackbar } from "./useSnackbar";
const Snackbar = ({ message }) => {
const { showSnackbar } = useSnackbar();
return (
showSnackbar && (
<div>
<p>{message}</p>
</div>
)
);
};
export { Snackbar };
useSnackbar.js
import { useState, useEffect } from 'react';
const useSnackbar = () => {
const [showSnackbar, setSnackbar] = useState(true);
const [snackbarMessage, setSnackbarMessage] = useState('');
useEffect(() => {
const timer = setTimeout(() => {
setSnackbar(false);
setSnackbarMessage('');
}, 3000);
return () => {
clearTimeout(timer);
};
}, [showSnackbar]);
return {
showSnackbar,
setSnackbar,
snackbarMessage,
setSnackbarMessage
};
};
export { useSnackbar };
答案 0 :(得分:1)
的确,useSnackbar
钩对true
的默认值为showSnackbar
,并且确实在3秒后变为false
,但在display
App.js
停留在true
上,这意味着即使在timeout
之后。
由于display
从未设置为false
,因此Snackbar
从未卸载,因此useSnackbar
的状态也从未重新初始化。
我的建议是更改useSnackbar
的使用方式。
我将useSnackbar
移到App.js
并在其中设置小吃栏打开状态。
function App() {
const { showSnackbar, setSnackbar } = useSnackbar();
return (
<div>
<button onClick={() => setSnackbar(true)}>Click me</button>
{showSnackbar && <Snackbar message="hello" />}
</div>
);
}
const useSnackbar = () => {
const [showSnackbar, setSnackbar] = useState(false);
// rest of code
};
const Snackbar = ({ message }) => (
<div>
<p>{message}</p>
</div>
);
还有其他方法来构造您的组件,但是对于您的示例,这将是最简单的解决方案之一。
答案 1 :(得分:1)
您不会在App.js中重置display
状态
将重置状态回调函数传递到Snackbar
,以传递到useSnackbar
挂钩。
const useSnackbar = (onClose) => { // <-- callback function
const [showSnackbar, setSnackbar] = useState(true);
const [snackbarMessage, setSnackbarMessage] = useState('');
useEffect(() => {
const timer = setTimeout(() => {
setSnackbar(false);
setSnackbarMessage('');
onClose && onClose(); // <-- invoke when timer expired
}, 3000);
return () => {
clearTimeout(timer);
onClose && onClose(); // <-- edge case if component unmounts before expire
};
}, [onClose, showSnackbar]);
return {
showSnackbar,
setSnackbar,
snackbarMessage,
setSnackbarMessage
};
};
const Snackbar = ({ message, onClose }) => {
const { showSnackbar } = useSnackbar(onClose); // <-- pass callback to hook
return (
showSnackbar && (
<div>
<p>{message}</p>
</div>
)
);
};
export default function App() {
const [display, setDisplay] = useState(false);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div>
<button onClick={() => setDisplay(true)}>Click me</button>
{display && <Snackbar message="hello" onClose={() => setDisplay(false)} />} // <-- pass reset callback
</div>
</div>
);
}