#javascript #reactjs #react-hooks #setstate #use-state
#javascript #reactjs #реагирующие крючки #setstate #use-state
Вопрос:
У меня есть snack bar component
, который отображает всплывающее сообщение в течение нескольких секунд, а затем исчезает. У меня есть App component
, который содержит a button
, и при нажатии button
на него я хочу управлять snack bar component
. При первом щелчке snack bar
отображается нормально и исчезает по истечении указанного времени. Но когда я нажимаю на него снова, snack bar
оно не появляется. Я каждый раз инициализирую значение show state
true, но оно все равно snack bar
не появляется. Пожалуйста, скажите мне, где я ошибаюсь и как это исправить. Ниже приведены файлы. Я использую пользовательский хук для управления поведением внешнего вида 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 amp;amp; <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 amp;amp; (
<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 };
Ответ №1:
Вы не сбрасываете свое display
состояние в App.js
Решение
Передайте функцию обратного вызова состояния сброса Snackbar
, чтобы перейти к useSnackbar
перехвату.
const useSnackbar = (onClose) => { // <-- callback function
const [showSnackbar, setSnackbar] = useState(true);
const [snackbarMessage, setSnackbarMessage] = useState('');
useEffect(() => {
const timer = setTimeout(() => {
setSnackbar(false);
setSnackbarMessage('');
onClose amp;amp; onClose(); // <-- invoke when timer expired
}, 3000);
return () => {
clearTimeout(timer);
onClose amp;amp; 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 amp;amp; (
<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 amp;amp; <Snackbar message="hello" onClose={() => setDisplay(false)} />} // <-- pass reset callback
</div>
</div>
);
}
Ответ №2:
Это правда, что useSnackbar
перехват имеет значение по умолчанию true
for showSnackbar
, и оно изменяется на false
через 3 секунды, но display
App.js
остается true
, что означает, что даже после timeout
.
Поскольку display
никогда не устанавливается значение false
, Snackbar
никогда не размонтируется, поэтому состояние useSnackbar
никогда не инициализируется повторно.
Мое предложение состояло бы в том, чтобы изменить структуру использования useSnackbar
.
Я бы перешел useSnackbar
в App.js
и установил там открытые состояния snackbar.
function App() {
const { showSnackbar, setSnackbar } = useSnackbar();
return (
<div>
<button onClick={() => setSnackbar(true)}>Click me</button>
{showSnackbar amp;amp; <Snackbar message="hello" />}
</div>
);
}
const useSnackbar = () => {
const [showSnackbar, setSnackbar] = useState(false);
// rest of code
};
const Snackbar = ({ message }) => (
<div>
<p>{message}</p>
</div>
);
Существуют и другие способы структурирования компонентов, но для вашего примера это было бы одним из самых простых решений.