Значение по умолчанию в useState не инициализируется повторно

#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>
  );
}
  

Редактировать значение по умолчанию в usestate, которое не инициализируется повторно

Ответ №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>
);
  

Демонстрация Code Sandbox

Существуют и другие способы структурирования компонентов, но для вашего примера это было бы одним из самых простых решений.