简体   繁体   English

使用 state 的道具替代组件

[英]Alternative to component using props for state

I have a bottom level component that is used to display success/ error messaging in my application.我有一个底层组件,用于在我的应用程序中显示成功/错误消息。 Currently it is using props for it's state, which has worked up until this point.目前它正在为它的 state 使用道具,直到这一点。 The problem I'm facing is when returned in a certain component the state isn't changing once the component is rendered once.我面临的问题是,当在某个组件中返回时,state 在组件渲染一次后不会改变。 IE The message will show up once correctly and then it doesn't show up again because the state stays set to false. IE 消息将正确显示一次,然后不再显示,因为 state 保持设置为 false。

Here is the function that renders the component.这是渲染组件的 function。 This function sits in the parent component.这个 function 位于父组件中。

renderSnackBar(type, message) {

    console.log('snackbar function invoked');

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

Here is the child component这是子组件

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;

From what I gather using props to initialize state is an antipattern.从我收集到的使用道具初始化 state 是一种反模式。 How can I use this component without using props as state?如何在不使用 state 的道具的情况下使用此组件?

Basically, the problem you have right now is caused by the fact that you have 2 sources of truth (1 from props, and 1 from state) for determining whether your SnackBar should open or not.基本上,您现在遇到的问题是由于您有 2 个事实来源(1 个来自道具,1 个来自状态)来确定您的 SnackBar 是否应该open

So, what we want to do is to make it so that there is only 1 source of truth for your component.所以,我们要做的是让你的组件只有一个事实来源。 Usually, we want to keep the props as the source of truth, not the state .通常,我们希望将props作为事实来源,而不是state

What we could do is to add a prop called onClose to your SnackBar, and have the SnackBar invoke the function inside handleClose .我们可以做的是给你的 SnackBar 添加一个名为onClose的道具,并让 SnackBar 在handleClose中调用 function 。 onClose should change the open value from the parent component, so the value passed down to SnackBar is updated accordingly. onClose应该更改父组件的open值,因此传递给 SnackBar 的值会相应更新。 Now, the SnackBar does not have to have its own state anymore, it can just rely on the props passed to it.现在,SnackBar 不再需要拥有自己的 state,它可以只依赖传递给它的道具。 Here is an example implementation on codesandbox .这是代码沙箱的示例实现

Whenever you receive the open prop that is not the same as state you can change state with getDerivedStateFromProps每当您收到与 state 不同的开放道具时,您都可以使用 getDerivedStateFromProps 更改state

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;
}

You may now have a component that doesn't close anymore depending on how you call renderSnackbar, if that's the case then I need to know more on how you call the renderSnackbar function.您现在可能有一个不再关闭的组件,具体取决于您如何调用 renderSnackbar,如果是这种情况,那么我需要了解更多关于如何调用 renderSnackbar function 的信息。

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

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