Recursive data & components, later fetches throwing an error

青春壹個敷衍的年華 提交于 2019-12-07 10:31:35

问题


First off my graphql data model:

type Human {
  id: !String,
  name: !String,
  children: [Human]
}

The only route (relay route config) I'm atm using:

class extends Relay.Route {
  static queries = {
    human: () => Relay.QL`query RootQuery { viewer }`
  };
  static routeName = 'AppHomeRoute';
}

The list component:

class HumanList extends Component {
  render() {
    let {children} = this.props.human;

    let subListsHTML = human ? children.map(child => (
      <HumanListItem key={child.id} human={child}/>
    )) : '';

    return <ul>{subListsHTML}</ul>;
  }
}

export default Relay.createContainer(HumanList, {
  fragments: {
    human: () =>  Relay.QL`
      fragment on Human {
        children {
          id,
          ${HumanListItem.getFragment('human')}
        }
      }
    `
  }
});

The list item component:

class HumanListItem extends Component {
  state = {expanded: false};

  render() {
    let {human} = this.props;

    let sublistHTML = '';
    if (this.state.expanded) {
      sublistHTML = <ul><HumanList human={human}/></ul>;
    }

    return (
      <li>
        <div onClick={this.onClickHead.bind(this)}>{human.name}</div>
        {sublistHTML}
      </li>
    );
  }

  onClickHead() {
    this.props.relay.setVariables({expanded: true});
    this.setState({expanded: true});
  }

}

HumanListItem.defaultProps = {viewer: {}};

export default Relay.createContainer(HumanListItem, {

  initialVariables: {
    expanded: false
  },

  fragments: {
    human: (variables) =>  Relay.QL`
      fragment on Human {
        name,
        ${HumanList.getFragment('human').if(variables.expanded)}
      }
    `
  }

});

Which runs fine for the root list. But as soon as I click on a ListItem and it is expanded, I get the following error:

Warning: RelayContainer: Expected prop 'human' supplied 'HumanList' to be data fetched by Relay. This is likely an error unless you are purposely passing in mock data that conforms to the shape of this component's fragment.

I can't make much sense of it, since the data I'm passing is not mocked but directly fetched by Relay as can be seen in the HumanList comp.


回答1:


The error indicates that the <HumanList> is being rendered before its data is ready.

class HumanListItem extends Component {
  onClickHead() {
    this.props.relay.setVariables({expanded: true});
    this.setState({expanded: true});  // <-- this causes the component to re-render before data is ready
  }

Rather than using state, you can instead look at the current value of the variables:

class HumanListItem extends Component {
  // no need for `state.expanded`

  render() {
    let {human} = this.props;

    let sublistHTML = '';
    if (this.props.relay.variables.expanded) {
      // `variables` are the *currently fetched* data
      // if `variables.expanded` is true, expanded data is fetched
      sublistHTML = <ul><HumanList human={human}/></ul>;
    }

    return (
      <li>
        <div onClick={this.onClickHead.bind(this)}>{human.name}</div>
        {sublistHTML}
      </li>
    );
  }

  onClickHead() {
    this.props.relay.setVariables({expanded: true});
    // no need for `setState()`
  }

}

HumanListItem.defaultProps = {viewer: {}};

export default Relay.createContainer(HumanListItem, {

  initialVariables: {
    expanded: false
  },

  fragments: {
    human: (variables) =>  Relay.QL`
      fragment on Human {
        name,
        ${HumanList.getFragment('human').if(variables.expanded)}
      }
    `
  }

});


来源:https://stackoverflow.com/questions/32497759/recursive-data-components-later-fetches-throwing-an-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!