反应状态挂钩不传递对元素的更改

时间:2020-03-20 09:12:27

标签: reactjs

我有以下(简化)代码:

import React, { useState, useEffect } from "react";
import Button from '@material-ui/core/Button';
import Snackbar from '@material-ui/core/Snackbar';
import MuiAlert from '@material-ui/lab/Alert';

const CheckIn = props => {
  const [success, setSuccess] = useState(false);
  const [error, setError] = useState(false);

  const handleClick = () => {
    //send request to checkin :)
    setSuccess(true);
  }

  return (
    <>
      <Button color="default" variant="contained" onClick={handleClick}>Check-in</Button>
      <Alert open={success} severity="success">Succes</Alert>
      <Alert open={error} severity="error">Error</Alert>
    </>
  )
}

const Alert = props => {
  const [open, setOpen] = useState(props.open);

  const handleClose = () => {
    setOpen(false);
  }

  return (
    <Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
      <MuiAlert severity={props.severity} onClose={handleClose}>
        {props.children}
      </MuiAlert>
    </Snackbar>
  )
}

我的期望是,当从CheckIn组件中按下按钮时,success变量将设置为true并传递到Alert组件,这将打开Snackbar并显示屏幕上的警报。之后的6秒钟,Snackbar会触发handleClose并再次关闭警报。

现在发生的是警报从不弹出。我尝试过的是将Snackbar open={open}更改为Snackbar open={props.open},以检查是否从父级正确传递了属性,该方法可以正常工作,但此后将无法关闭警报。

我主要是在寻找为什么它不起作用的原因,而不是一种解决方法。

1 个答案:

答案 0 :(得分:1)

当前在Alert中设置setOpen仅在Alert中设置本地状态,但在CheckIn中打开未更改。无需复制道具,您可以将功能从CheckIn传递给Alert来更改CheckIn中的打开值。

由于警报(及其关闭按钮)仅在打开状态为true时显示,因此您可以通过切换关闭警报。

const CheckIn = () => {
  const [success, setSuccess] = React.useState(true);
  const [error, setError] = React.useState(true);

  const toggleSuccess = React.useCallback(
    () => setSuccess(success => !success),
    []
  );
  const toggleError = React.useCallback(
    () => setError(error => !error),
    []
  );

  return (
    <React.Fragment>
      <button onClick={toggleSuccess}>
        toggle success
      </button>
      <button onClick={toggleError}>toggle error</button>
      <div>
        <Alert open={success} close={toggleSuccess}>
          Succes
        </Alert>
        <Alert open={error} close={toggleError}>
          Error
        </Alert>
      </div>
    </React.Fragment>
  );
};

const Alert = ({ open, close, children }) => {
  return open ? (
    <React.Fragment>
      {children}
      <div>
        <button onClick={close}>close</button>
      </div>
    </React.Fragment>
  ) : (
    ''
  );
};

ReactDOM.render(
  <CheckIn />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>