React - 在 <option> 更新时更新 <select>

React - update <select> when <option> updated

我制作了一个简单的组件来填充 <select> 来自 REST 或本地数组的条目数组。代码使用如下:

<ComboBox id="TestAsync" label="Country List" default="DE" onChange={this.change}>
    <DataSource source="/api/region/country" idField="id" captionField="name" />
</ComboBox>

<ComboBox>基本上是用select的语句,但是用<DataSource>检测。下面是<ComboBox>渲染代码

constructor(props: IField) {
    super(props);
    this.state = {
        value: props.default
    }
}

public componentDidUpdate(prevProps: IField, prevStat: IState) {
    if (prevProps.default != this.props.default) this.setState({ value: this.props.default });
}

render() {
    return <div className="hx-field" id={this.props.id}>
        <label>{this.props.label}</label>
        <select name={this.props.id} onChange={this.onChangeSelect.bind(this)} value={this.state.value} disabled={this.props.readonly} key={this.props.id}>
            {this.props.children}
        </select>
    </div>
}    

这是 <Datasource> class:

export class DataSource extends React.Component<IDataSource, IDataSourceState> {

    constructor(props: IDataSource<T>) {
        super(props);
        this.state = {
            rawData: null,
            options: [
                <option value="">Loading ... </option>
            ]
        }
    }

    private option(item): JSX.Element {
        return <option value={item[this.props.idField]} key={item[this.props.idField]}>{item[this.props.captionField]}</option>
    }

    private load() {
        Adapter.load(this.props)
            .then(result => {
                if (!result) return;
                this.setState({
                    rawData: result,
                    options: result.map(x => this.option(x))
                })
            })
            .catch(error => {
                console.error("DataSource load error: Cannot load REST data");
                console.error(error);
            })
    }

    public render() {
        return this.state.options;
    }
}

代码有效,但有一个例外。我无法向它发送默认值。我认为当 <select> 组件的值呈现时,数据源仍然是空的。但是当我在数据源填充后发送值时,代码工作正常。即从组合框中选择一个选项。

如何在 <datasource> 修改时强制更新 <select> 组件?

一种方法是在 <option>:

上使用 selected 道具
export class DataSource extends React.Component<IDataSource, IDataSourceState> {
//    ...
  private option(item): JSX.Element {
     const {idField, captionField} = this.props;
     const {[idField]: id, [captionField]: caption} = item;
     return 
        <option 
           value={id} 
           key={id}
           selected={id===this.props.value}
        >
        {caption}
        </option>
   }

这样我们需要将实际的 value 传递给 DataSource 否则我们的默认值将永远不会改变:

<ComboBox id="TestAsync" label="Country List" onChange={this.changeCountryListValue}>
    <DataSource source="/api/region/country" idField="id" captionField="name" selected={this.countryListValue || 'DE'} />
</ComboBox>

或者您可以通过注入 onLoad 回调或提供 selected 值来使 ComboBox 修改嵌套 DataSource,就像我在上面以直接方式所做的那样。 React.children.mapReact.cloneElement to rescue on that.

最后,您可以将所有加载数据移出 ComboBox 到父元素或某些包装器。我宁愿遵循这种方式,因为目前您的通用命名 DataSource 将数据加载并将项目呈现到 <option> 中,这违反了单一责任原则。这可能不允许您在不同的上下文中使用它(当您需要加载相同的数据但显示在不同的组件而不是 <option>