简体   繁体   English

useState 中的默认值未重新初始化

[英]Default value in useState not getting re-initialised

I have a snack bar component , which displays a toast message for a few seconds and then disappears.我有一个snack bar component ,它会显示一条吐司消息几秒钟然后消失。 I have an App component which contains a button , and on click of that button , I want to control the snack bar component .我有一个App component ,其中包含一个button ,单击该button ,我想控制snack bar component On the first click, the snack bar appears fine and disappears after the time specified is over.在第一次单击时, snack bar显示正常,并在指定的时间结束后消失。 But when I click it again, the snack bar doesn't appear.但是当我再次单击它时, snack bar不会出现。 I am initializing the show state to true every time, still, the snack bar isn't appearing.我每次都将show state初始化为 true,但仍然没有出现snack bar Please tell me where I am going wrong and how to rectify this.请告诉我哪里出错了以及如何纠正。 Below are the files.下面是文件。 I am using a custom hook to control the behavior of snack bar's appearance.我正在使用自定义钩子来控制小吃店外观的行为。

App.js应用程序.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 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使用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 };

It's true that the useSnackbar hook has a default value of true for showSnackbar and it does get changed to false after 3 seconds but display in App.js stays true which means that even after the timeout .该这是真的useSnackbar钩有一个默认值trueshowSnackbar和它得到改变为false后3秒,但displayApp.js保持true这意味着即使后timeout

Since display never gets set to false , Snackbar never gets unmounted so the state of useSnackbar never gets reinitialized.由于display永远不会被设置为falseSnackbar永远不会被卸载,所以useSnackbar的状态永远不会被重新初始化。

My suggestion would be to change the structure of how useSnackbar is being used.我的建议是改变useSnackbar的使用结构。

I'd move useSnackbar into App.js and set the snackbar open states there.我将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>
);

Code Sandbox Demo 代码沙盒演示

There are other ways to structure thee components but for your example, this would be one of the simplest solutions.还有其他方法可以构建这些组件,但对于您的示例,这将是最简单的解决方案之一。

You don't reset your display state in App.js您不会在 App.js 中重置您的display状态

Solution解决方案

Pass a reset state callback function to Snackbar to pass to the useSnackbar hook.将重置状态回调函数传递给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>
  );
}

编辑 default-value-in-usestate-not-getting-re-initialised

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM