【问题标题】:Default value in useState not getting re-initialiseduseState 中的默认值未重新初始化
【发布时间】:2021-01-19 17:09:31
【问题描述】:

我有一个snack bar component,它会显示一条 toast 消息几秒钟然后消失。我有一个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 };

【问题讨论】:

    标签: javascript reactjs react-hooks setstate use-state


    【解决方案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>
      );
    }
    

    【讨论】:

      【解决方案2】:

      确实,useSnackbar 钩子对于 showSnackbar 的默认值为 true,并且在 3 秒后它确实更改为 false,但 App.js 中的 display 保持 true,这意味着即使在timeout 之后。

      由于display 永远不会被设置为falseSnackbar 永远不会被卸载,因此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>
      );
      

      Code Sandbox Demo

      还有其他构建组件的方法,但对于您的示例,这将是最简单的解决方案之一。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-29
        • 2022-12-21
        • 2020-02-08
        • 2019-10-04
        相关资源
        最近更新 更多