(反应)侦听由传播为道具的更改数据列表触发的下拉/选择值更改

时间:2018-06-25 08:49:18

标签: javascript reactjs browser

我正在使用一个简单的HTML select下拉列表,并使用react(==>受控组件)对其进行控制。到目前为止一切都很好。问题是-select选项通过异步ajax调用每隔几秒钟更新一次,并在开始时为空。选择数据列表通过道具传播。

因此,选择数据列表发生变化,所选选项列表发生变化-但未触发任何更改(afaik由react设计)。 我发现了一种有效的方法来监听这些更改,方法是侦听“ componentDidUpdate”,并通过读出select的值作为参考来“手动”触发onChange,但这似乎非常“不反应”(下面的代码) 。有人知道这样做的“反应”方式吗?

完整代码:

class Dropdown extends React.Component {
    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.dropDown = React.createRef();      
    }

    handleChange(event) {
        if (this.props.onChange) this.props.onChange(event.target.value);
    }

    componentDidUpdate(prevProps) {
        if (this.props.options.length != prevProps.options.length) {
            if (this.props.onChange) this.props.onChange(this.dropDown.current.value);
        } else {
            for (let i = 0; i < this.props.options.length; i++) {
                if (this.props.options.value != prevProps.options.value) {
                    if (this.props.onChange) this.props.onChange(this.dropDown.current.value);
                    return;
                }
            }
        }
    }

    render() {
        const optionList = this.props.options.map(option => <option value={option.value} key={option.value}>{option.name}</option>);
        return <select value={this.props.value} onChange={this.handleChange} ref={this.dropDown}>{optionList}</select>;
    }
}

props.options从空列表开始。某些父节点将此列表作为状态保存,并每隔几秒钟通过ajax请求对其进行更新。

沙盒代码:https://codesandbox.io/s/6l927kpx13

2 个答案:

答案 0 :(得分:0)

您应该将道具传递给状态。

state = {
    options: this.props.options,
}

渲染方法:

render() {
    const optionList = this.state.options.map((option, index) => (
      <option key={index} value={option.price}>{option.price}</option>
    ));

    return (
      <select>{optionList}</select>
    );
  }

道具更改侦听器:

componentDidUpdate(prevProps) {
    if (this.props.options[0].price !== prevProps.options[0].price) {
      this.setState({
        options: this.props.options,
      });
    }
  }

尝试使用此代码和框https://codesandbox.io/s/pjky3r4z60

答案 1 :(得分:0)

React通过查看组件的道具和状态来处理它的更新。现在,您实施它的方式几乎是正确的,只要您调用setState(),就会触发重新渲染。 但是,您要查找的onChange事件不是每当动态更新您的选项时,而是在用户选择其他选项时触发的。这与React无关。

如果您想以更有效的方式检查更新,请参阅Rizal Ibnu提供的答案。

但是,我会在您的代码中添加一些更新,它可能会更短:

class Dropdown extends React.Component {
    constructor(props) {
        super(props);
    }

    // You can 'bind' this also with an arrow function
    handleChange = event => {
        if (this.props.onChange) this.props.onChange(event.target.value);
    };

    componentDidUpdate(prevProps) {
        if (this.props.options.length != prevProps.options.length) {
            if (this.props.onChange) this.props.onChange(this.dropDown.current.value);
        } else {
                this.props.options.forEach(() => {
                    if (this.props.options.value != prevProps.options.value) {
                        if (this.props.onChange)
                            this.props.onChange(this.dropDown.current.value);
                        return;
                    }
                })
            }
        }
    }

    render() {
        return (
            <select
                value={this.props.value}
                onChange={this.handleChange}
                // Consider using callback refs
                ref={dropdown => (this.dropDown = dropDown)}
            >
                // Pure preference, I like mapping a list inline
                {this.props.options.map(option => (
                    <option value={option.value} key={option.value}>
                        {option.name}
                    </option>
                ))}
            </select>
        );
    }
}

我会再看看您父母的this.props.onChange方法,我认为它应该是未定义的。