useState 中的默认值未重新初始化
Default value in useState not getting re-initialised
我有一个 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 };
使用Snackbar.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 };
确实 useSnackbar
钩子对于 showSnackbar
的默认值为 true
并且它确实在 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>
);
还有其他构造组件的方法,但对于您的示例,这将是最简单的解决方案之一。
您没有在 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>
);
}
我有一个 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 };
使用Snackbar.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 };
确实 useSnackbar
钩子对于 showSnackbar
的默认值为 true
并且它确实在 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>
);
还有其他构造组件的方法,但对于您的示例,这将是最简单的解决方案之一。
您没有在 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>
);
}