我正在使用一个简单的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请求对其进行更新。
答案 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
方法,我认为它应该是未定义的。