如何处理对话框组件外部的对话框状态?

时间:2019-05-16 18:37:45

标签: reactjs

我有以下对话框组件:

class LoginDialog extends React.Component {
  state = {
    open: false,
  };

  openDialog = () => {
    this.setState({ open: true });
  };

  handleClose = () => {
    this.setState({ open: false });
  };

  render() {
    return (
      <div>
        <Dialog
          open={this.state.open}
          onClose={this.handleClose}
        >
          <DialogActions>
            <Button onClick={this.handleClose} color="primary">
              Cancel
            </Button>
            <Button onClick={this.handleClose} color="primary">
              Subscribe
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}

如何从父组件打开该对话框并确保关闭对话框也能正常工作?这是我的尝试

class MainAppBar extends React.Component {
    state = {
    openLoginDialog: false,
    openRegisterDialog: false
    };
    render() {
        return (
            <div>
                <Button color="inherit" onClick={this.state.openLoginDialog}>Login</Button>
                )}
                <LoginDialog /*not sure how to pass here openLoginDialog*//>
            </div>
        );
    }
}

所以我不确定我是否真的必须在子/父/母中都保留对话状态,以及如何正确地从父/母中打开对话状态。

4 个答案:

答案 0 :(得分:1)

无论父级中登录对话框是否打开,都必须保持状态。将打开/关闭状态传递给子项,然后通过回调将其通过props关闭向子项的对话框。

class MainAppBar extends React.Component {
  state = {
    openLoginDialog: false,
    openRegisterDialog: false
  };

  openLoginDialog = () => {
    this.setState({
      openLoginDialog: true
    });
  };

  closeLoginDialog = () => {
    this.setState({
      openLoginDialog: false
    });
  };
  render() {
    return (
      <div>
        <Button color="inherit" onClick={() => this.openLoginDialog()}>
          Login
        </Button>
        )}
        <LoginDialog
          closeLoginDialog={this.closeLoginDialog}
          isLoginDialogOpen={this.state.openLoginDialog}
        />
      </div>
    );
  }
}

此组件不需要任何状态管理,因为我们在父级中对其进行管理。我们可以这样制作:

const LoginDialog = props => (
  <div>
    <Dialog open={props.isLoginDialogOpen} onClose={props.closeLoginDialog}>
      <DialogActions>
        <Button onClick={props.closeLoginDialog} color="primary">
          Cancel
        </Button>
        <Button onClick={props.closeLoginDialog} color="primary">
          Subscribe
        </Button>
      </DialogActions>
    </Dialog>
  </div>
);

希望这会有所帮助!

答案 1 :(得分:0)

您可以在MainAppBar组件内定义handleClose()或等效的事件处理程序,并将其传递给子级。它可以管理Parent上的状态变量(真/假),并将该布尔值传递到LoginDialog栏中以确定是否应打开它们。这样,孩子的状态将由父母管理。

class MainAppBar extends React.Component {
    state = {
    openLoginDialog: false,
    openRegisterDialog: false
    };

    toggleDialog = () => {
       this.setState((prevState) => {
          return{
             openLoginDialog: !prevState.openLoginDialog
          }
       })
    }

    render() {
        return (
            <div>
                <Button color="inherit" onClick={this.state.openLoginDialog}>Login</Button>
                )}
                <LoginDialog open={this.state.openLoginDialog} toggle={this.toggleDialog}/>
            </div>
        );
    }
}

然后:

class LoginDialog extends React.Component {

  render() {
    return (
      <div>
        <Dialog
          open={this.props.open}
          onClose={() => this.props.toggle} //not sure what this listener does, but im assuming you want to close it
        >
          <DialogActions>
            <Button onClick={() => this.props.toggle} color="primary">
              Cancel
            </Button>
            <Button onClick={() => this.props.toggle} color="primary">
              Subscribe
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}

答案 2 :(得分:0)

如果让父组件管理对话框的状态,则可以将其完全控制,同时将控制功能传递给对话框元素本身:

class MainAppBar extends React.Component {
        constructor(props) {
            this.state = {
                openLoginDialog: false,
                openRegisterDialog: false
            };
        }

        closeDialog() {  // This method will be passed to the dialog component
            this.setState({
                openLoginDialog: false
            });
        }

        render() {
            return (
                <div>
                    <Button color="inherit" onClick={this.state.openLoginDialog}>Login</Button>
                    )}
                    <LoginDialog isOpen={this.state.openLoginDialog} closeDialog={this.closeDialog}>
                </div>
            );
        }
    }

class LoginDialog extends React.Component {
  render() {
    return (
      <div>
        <Dialog
          open={this.props.isOpen}
          onClose={this.props.closeDialog}
        >
          <DialogActions>
            <Button onClick={this.props.closeDialog} color="primary">
              Cancel
            </Button>
            <Button onClick={this.props.closeDialog} color="primary">
              Subscribe
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}

答案 3 :(得分:0)

我将采用与其他答案不同的方法,并且仅在需要时才包含LoginDialog

我们现在可以使LoginDialog成为功能组件,并使lift the state up成为Parent组件。现在我们的LoginDialog更简单,更容易测试,而且不依赖任何东西

class Parent extends React.Component {
  state = {
    isOpen: false,
  };

  // No need to use open and close handler because if the modal
  // is open another execute of the function will close it
  // this way we can still toggle it from the button that's opening the Dialog
  toggleDialog = () => {
    this.setState(prevState => ({
      open: !prevState.open,
    }));
  };

  // if you want make the handler more flexible you can write it like this
  // make it a toggle by default with an optional nextState to
  // make it more flexible
  dialogStateHandler = (nextState) => () => {
    this.setState(prevState => ({
      open: nextState || !prevState.open,
    }));
  };
  // to use this handler you will need to invoke it and passing
  // in the nextState or without to make it toggle
  // onClick={this.dialogStateHandler(true / false || without args to toggle)}

  render() {
    const { isOpen } = this.state;

    return (
      <div>
        <button onClick={this.toggleDialog}>Toggle</button>
        {/* include the Dialog component only when its open */}
        {isOpen && <LoginDialog closeDialog={this.toggleDialog} />}
      </div>
    );
  }
}

closeDialog接收Parent作为道具,并将其传递给Child组件

const LoginDialog = ({ closeDialog }) => (
  <div>
    <Dialog
      closeDialog={closeDialog}
    >
      <DialogActions>
        <Button onClick={closeDialog} color="primary">
          Cancel
        </Button>
        <Button onClick={closeDialog} color="primary">
          Subscribe
        </Button>
      </DialogActions>
    </Dialog>
    )}
  </div>
);