替代使用道具进行状态展示的组件

时间:2019-09-26 02:09:14

标签: reactjs

我有一个底层组件,用于在我的应用程序中显示成功/错误消息。目前,它使用状态的道具,直到现在为止。我面临的问题是,在某个组件中返回该组件后,状态不会改变。即该消息将正确显示一次,然后再显示一次,因为状态保持为false。

这是渲染组件的函数。此函数位于父组件中。

renderSnackBar(type, message) {

    console.log('snackbar function invoked');

    return <Snackbar open={true} type={type} message={message} />
  }

这是子组件

class MySnackbar extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
    open: this.props.open,
  };
}

  handleClose = (event, reason) => {
    if (reason === 'clickaway') {
      return;
    }

    this.setState({ open: false });
  };

  render() {

    const { type, message } = this.props

    let icon = <SuccessIcon color={colors.lightBlue} />
    let color = colors.lightBlue
    console.log('state', this.state, 'props', this.props);

    switch (type) {
      case 'Error':
        icon = <ErrorIcon color={colors.red} />
        color = colors.red
        break;
      case 'Success':
        icon = <SuccessIcon color={colors.lightBlue} />
        color = colors.lightBlue
        break;
      case 'Warning':
        icon = <WarningIcon color={colors.orange} />
        color = colors.orange
        break;
      case 'Info':
        icon = <InfoIcon color={colors.lightBlue} />
        color = colors.lightBlue
        break;
      default:
        icon = <SuccessIcon color={colors.lightBlue} />
        color = colors.lightBlue
        break;
    }

    return (
      <Snackbar
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'left',
        }}
        open={this.state.open}
        autoHideDuration={6000}
        onClose={this.handleClose}
        message={
          <div style={{ padding: '12px 24px', borderLeft: '5px solid '+color, borderRadius: '4px'}}>
            {icon}
            <div style={{ display: 'inline-block', verticalAlign: 'middle', maxWidth: '400px' }}>
              <Typography variant='body1' style={{ fontFamily: 'Montserrat-SemiBold', fontSize: '12px' }}>{type}</Typography>
              <Typography variant='body1' style={{ fontFamily: 'Montserrat-Medium', fontSize: '10px', color: colors.darkGray }} noWrap>{message}</Typography>
            </div>
          </div>
        }
        action={[
          <IconButton
            key="close"
            aria-label="Close"
            color={colors.darkGray}
            onClick={this.handleClose}
          >
            <CloseIcon />
          </IconButton>,
        ]}
      />
    );
  }
}

export default MySnackbar;

根据我使用道具收集的用于初始化状态的信息,它是一种反模式。如何在不使用道具作为状态的情况下使用此组件?

2 个答案:

答案 0 :(得分:1)

基本上,您现在遇到的问题是由以下事实引起的:您有2个真理来源(1个来自道具,而1个来自状态)来确定SnackBar是否应该open

因此,我们要做的是使它只有一个真相来源。通常,我们希望保留props作为真理的来源,而不是state

我们可以做的就是在您的SnackBar中添加一个名为onClose的道具,并让SnackBar在handleClose内部调用该函数。 onClose应该更改父组件的open值,因此传递给SnackBar的值将相应更新。现在,SnackBar不再必须具有自己的状态,它可以仅依赖传递给它的道具。 Here is an example implementation on codesandbox

答案 1 :(得分:0)

只要收到与状态不同的打开道具,就可以使用getDerivedStateFromProps更改状态

static getDerivedStateFromProps({open}, state) {
  if (open !==state.open) {
    //use open from props
    return {
      ...state,
      open
    };
  }  
  // Return null to indicate no change to state.
  return null;
}

根据您如何调用renderSnackbar,您现在可能会关闭一个组件,如果是这种情况,那么我需要进一步了解如何调用renderSnackbar函数。