等待反应状态/道具更新后再使用数据?

时间:2020-07-15 15:21:43

标签: javascript reactjs redux react-redux immutable.js

我在我的react应用程序中使用带有restore-store的react-redux。用户登录后,状态包含我要用于自定义应用程序并显示其名称和其他信息的用户数据。除非有人刷新页面,否则一切正常。

我添加了持久存储,因为我将在刷新时丢失状态值,并且显示未通过身份验证。现在可以正常工作,但是恢复状态似乎会有延迟。因此,如果我尝试在组件中使用用户名,则刷新后会崩溃,提示未定义。但是几秒钟后数据可用,因为我可以在console.log(this.props)中看到它

现在我对所有这些值都使用三元运算符,这是一个不错的解决方案,但是我想知道是否有一种方法可以等待数据被使用之前?

这是我的组成部分之一

TabContainer.propTypes = {
  children: PropTypes.node.isRequired,
};

class UserProfile extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      email: '',
      value: 0,
    };
  }

  componentDidMount() {
    const { fetchData } = this.props;
    fetchData(data);
  }

  handleChange = (event, value) => {
    this.setState({ value });
  };

  render() {
    const { login } = this.props;
    const title = brand.name + ' - Profile';
    const description = brand.desc;
    const { dataProps, classes } = this.props;
    const { value } = this.state;
    const name = login.user.name === undefined ? '' : shortenName(login.user.name);
    const group = login.user.groups === undefined ? '' : login.user.groups[0].name;
    const role =
      login.user.role === undefined
        ? ''
        : login.user.role.charAt(0).toUpperCase() + login.user.role.slice(1);
    
    return (
      <div>
        <Helmet>
          <title>{title}</title>
          <meta name="description" content={description} />
          <meta property="og:title" content={title} />
          <meta property="og:description" content={description} />
          <meta property="twitter:title" content={title} />
          <meta property="twitter:description" content={description} />
        </Helmet>
        <Cover
          coverImg={bgCover}
          avatar={dummy.user.avatar}
          name={name}
          desc={`${user.role.charAt(0).toUpperCase() + user.role.slice(1)} - ${group}`}
        />
        <AppBar position="static" className={classes.profileTab}>
          <Hidden mdUp>
            <Tabs
              value={value}
              onChange={this.handleChange}
              variant="fullWidth"
              indicatorColor="primary"
              textColor="primary"
              centered
            >
              <Tab icon={<AccountCircle />} />
              <Tab icon={<SupervisorAccount />} />
              <Tab icon={<Favorite />} />
              <Tab icon={<PhotoLibrary />} />
            </Tabs>
          </Hidden>
          <Hidden smDown>
            <Tabs
              value={value}
              onChange={this.handleChange}
              variant="fullWidth"
              indicatorColor="primary"
              textColor="primary"
              centered
            >
              <Tab icon={<AccountCircle />} label="ABOUT" />
              <Tab icon={<SupervisorAccount />} label="0 CONNECTIONS" />
              <Tab icon={<Favorite />} label="0 FAVORITES" />
              <Tab icon={<PhotoLibrary />} label="0 ALBUMS" />
            </Tabs>
          </Hidden>
        </AppBar>
        {value === 0 && (
          <TabContainer>
            <About data={dataProps} />
          </TabContainer>
        )}
        {value === 1 && (
          <TabContainer>
            <Connection />
          </TabContainer>
        )}
        {value === 2 && (
          <TabContainer>
            <Favorites />
          </TabContainer>
        )}
        {value === 3 && (
          <TabContainer>
            <Albums />
          </TabContainer>
        )}
      </div>
    );
  }
}

UserProfile.propTypes = {
  login: PropTypes.object.isRequired,
  classes: PropTypes.object.isRequired,
  dataProps: PropTypes.object.isRequired,
  fetchData: PropTypes.func.isRequired,
};

const reducer = 'socmed';
const mapStateToProps = state => ({
  force: state, // force state from reducer
  dataProps: state.getIn([reducer, 'dataTimeline']),
  login: state.get('login'),
});

const constDispatchToProps = dispatch => ({
  fetchData: bindActionCreators(fetchAction, dispatch),
});

const UserProfileMapped = connect(
  mapStateToProps,
  constDispatchToProps,
)(UserProfile);

export default withStyles(styles)(UserProfileMapped);

1 个答案:

答案 0 :(得分:1)

几种实现此目的的方法:

  1. 继续使用当前的方法,因为在render()中使用条件是在React中显示数据的有效且惯用的方式。
  2. 如果fetchData返回了一个承诺,请跟踪加载状态,直到承诺完成后才渲染任何内容。
constructor(props) {
   super(props);
   this.state = {
      email: '',
      value: 0,
      isLoading: true,
   };
}

componentDidMount() {
   const { fetchData } = this.props;
   fetchData(data)
      .then(() => {
         this.setState({isLoading: false})
      })
      .catch((e) => {
         console.error(e);
         this.setState({isLoading: false})
      });
}

render() {
   const {isLoading} = this.state;
   
   if (isLoading) {
      return null;
   }

   ...
   // Remove the conditional around user
   ...
}