javascript - 确保父项仅在加载所有子项时显示

标签 javascript reactjs

我对 react 很陌生,我正在努力解决以下问题。我在 react 中创建了一个表单,该表单包含一个下拉列表。我需要在多个页面中重用该下拉菜单,因此我想将其作为一个组件来完全负责获取所有数据。

在表单组件中,我获取所有数据,其中一个字段是 selectedServerDataId。 selectId 字段包含需要在下拉列表中选择的值的 ID。

<snip includes/>

class Arrival extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            formData: {}
        };
    }

   async componentDidMount() {
        await fetch(urls.addEditUrl)
            .then(response => response.json())
            .then(data => {
                this.setState({ formData: data });
            });
    }

    <snip some setstate helpers/>

    render() {
        const { formData } = this.state;
        return (
                <Form >
                <Selector label="select"
                    onChange={this.UpdateFormSelectData.bind(this, 'selectedServerDataId')}
                    value={formData.selectedServerDataId}/>
                <DateItem label="date"
                          allowClear={true}
                          value={formData.date}
                          onChange={this.updateFormDateData.bind(this, 'date')}/>
                <snip more fields.../>
            </Form>);
    }
}

export default Arrival;

父组件中的提取检索编辑表单的数据,包括 selectedServerDataId。我的子组件如下所示:

<snip usings />

class ServerDataSelector extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            options: [],
        };
    }

    async componentDidMount() {
        await fetch(URLS.GetServerData)
            .then(response => response.json())
            .then(data => {
                this.setState({ options: data });
            });
    }

    render() {
        const { options } = this.state;
        return (
            <FormItem {...formItemLayout} label={t(this.props.label)} >
                <Select setValue={this.props.onChange} getValue={() => this.props.value} selectedOption={this.props.value} name={this.props.label}>
                        {options.map(d => <Option key={d.id} value={d.id}>{d.value}</Option>)}
                </Select>
                  //TODO add model window to manipulate list.
                </FormItem>);
    }
}

export default ServerDataSelector 
ServerDataSelector { Selector }

当前,当页面呈现时,我首先在下拉列表中看到所选值的 ID,然后一瞬间我看到了实际的所选值标签。

有没有办法确保父组件只在子组件完全加载完成时呈现?

最佳答案

您在这里遇到的主要问题是您有两个组件,它们具有严格的呈现层次关系(父 -> 子)但具有同等的数据获取责任。

这导致您必须以特定顺序对多个组件之间的数据检索使用react,这是一个非常重要的并发问题。一种解决方案是使用共享状态容器(使用 ReduxContext API )并让两个组件将它们的结果保存到这个共享状态桶中,然后只要桶中有所有数据,你就呈现它(直到那时你例如可以显示微调器)。

一个更简单的解决方案是将获取转移到一个组件中,完全消除这种分离的数据获取责任,并允许获取数据的组件也控制渲染。

一种方法是获取父级中的所有数据,让子级只是一个纯组件,在接收到数据时呈现:

class Arrival extends React.Component {
  // ...

  async componentDidMount() {
    const [formData, options] = await Promise.all([
      fetch(urls.addEditUrl).then(response => response.json()),
      fetch(URLS.GetServerData).then(response => response.json())
    ]);

    this.setState({ formData, options });
  }

  render() {
    const { formData, options } = this.state;
    return (
      <Form>
        {/* ... */}
        {formData &&
          options && (
            <Selector
              label="select"
              options={this.state.options}  {/* pass the options here */}
              onChange={this.UpdateFormSelectData.bind(
                this,
                "selectedServerDataId"
              )}
              value={formData.selectedServerDataId}
            />
          )}
      </Form>
    );
  }
}

Selector 现在只是一个展示组件,不需要状态:

const ServerDataSelector = props => (
  <FormItem {...formItemLayout} label={t(this.props.label)}>
    <Select
      setValue={this.props.onChange}
      getValue={() => this.props.value}
      selectedOption={this.props.value}
      name={this.props.label}
    >
      {this.props.options.map(d => (     {/* use props.options */}
        <Option key={d.id} value={d.id}>
          {d.value}
        </Option>
      ))}
    </Select>
  </FormItem>
);

您可以选择显示微调器或加载指示器:

...
{
  formData && options ? (
    <Selector
      label="select"
      onChange={this.UpdateFormSelectData.bind(this, "selectedServerDataId")}
      options={this.state.options}
      value={formData.selectedServerDataId}
    />
  ) : (
    <Spinner />
  );
}

或者,您可以让子项获取所有数据,而父项只渲染子项。

class ServerDataSelector extends React.Component {
  // ...

  async componentDidMount() {
    const [formData, options] = await Promise.all([
      fetch(urls.addEditUrl).then(response => response.json()),
      fetch(URLS.GetServerData).then(response => response.json())
    ]);

    this.setState({
      value: formData.selectedServerDataId,
      options
    });
  }

  render() {
    return (
      <FormItem {...formItemLayout} label={t(this.props.label)}>
        <Select
          setValue={this.props.onChange}
          getValue={() => this.state.value}  {/* use the value from the state */}
          selectedOption={this.state.value}  {/* use the value from the state */}
          name={this.props.label}
        >
          {this.state.options.map(d => (
            <Option key={d.id} value={d.id}>
              {d.value}
            </Option>
          ))}
        </Select>
      </FormItem>
    );
  }
}

您还可以在 child 中添加一个微调器以防止页面卡顿并允许更好的用户体验:

render() {
  if (!this.state.value || !this.state.options) {
    return <Spinner />;
  }

  return (
    <FormItem {...formItemLayout} label={t(this.props.label)}>
      <Select
        setValue={this.props.onChange}
        getValue={() => this.state.value}
        selectedOption={this.state.value}
        name={this.props.label}
      >
        {this.state.options.map(d => (
          <Option key={d.id} value={d.id}>
            {d.value}
          </Option>
        ))}
      </Select>
    </FormItem>
  );
}

关于javascript - 确保父项仅在加载所有子项时显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51116620/

相关文章:

reactjs - 从 mongoDB 获取数据、setstate 并将 props 传递给子组件不起作用

javascript - onclick on img 将链接到另一个页面上的特定部分

reactjs - 使用 webpack 为 Protractor 预处理 e2e 测试文件(ES6 样式)

Javascript ES6 ()=>() 和 ()=>{} 之间的区别

javascript - 基于span标签的div的Xpath

reactjs - 为什么toggleSelection 和isSelected 方法接收不同的关键参数?

javascript - 在 React 中父级触发的事件中将数据传递给子级

javascript - NextJS - 使用浅路由器推送时无法识别页面组件上发生状态更改的位置

javascript - 如何在 Angular 中滚动到特定点时触发函数?

javascript - 向下滚动页面时,表格行必须保持固定在顶部