react componentdidupdate 引发无限循环
react componentdidupdate provokes infinite loop
我使用 onChange
触发了对 elasticsearch 的 API 调用,以便我可以提示自动完成列表。
为了确保我的商店在重新渲染之前得到更新,我添加了 componentDidMount 这样我就不会落后一个滴答声。但是进入正题需要代码,所以:
constructor(props) {
super(props)
this.state = {
inputValue: '',
options: []
};
this.props = {
inputValue: '',
options: []
};
this._onChange = this._onChange.bind(this);
}
componentDidMount() {
CodeStore.addChangeListener(this._onChange);
}
_onChange(event) {
if (this.state.inputValue && !event) {
var enteredChars = this.state.inputValue;
console.log('NO EVENT!');
} else if (event.target.value) {
console.log('EVENT!');
var enteredChars = event.target.value;
this.setState({inputValue: enteredChars});
}
CodeService.nextCode(enteredChars);
}
如您所见,我添加了一些日志事件只是为了确保我的情况正常。我读到 setState
引发重新渲染,因此它在条件内,但并未停止循环。并且控制台日志确认条件切换。但是在我的条件中包含 setState
会阻止功能,我没有得到列表。
这是我的日志:
0
Home.jsx:48 EVENT!
Home.jsx:50 0
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
10OptionTemplate.jsx:15 render-list
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
10OptionTemplate.jsx:15 render-list
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
无限循环无论如何都不会影响性能。我认为是因为 componentWillUnmount
但必须避免大量 API 调用。希望这些信息足以提供任何证据。
您的输入事件和存储侦听器似乎都在使用 _onChange。他们需要不同的方法。
看起来无限循环是由以下模式引起的:
- 用户类型输入
- _onChange 更新状态 + 触发存储操作
- 商店自行更新并发送更改事件
- 商店更改事件触发 相同 _onChange 事件
- _onChange 不更新状态,但仍然触发存储操作
- 转到第 3 步并重复(无限期)
修复步骤:
- 为用户输入和商店更新制作不同的更改处理程序(正如@Janaka Stevens 已经建议的那样)
- 将存储中的数据放入状态
- 用户输入不必处于状态(如果您的 React 代码未向输入字段提供值,它将以空值开头,并保留任何键入的内容)
那么您的代码可能如下所示:
constructor(props) {
super(props)
this.state = {
options: []
};
// removed the this.props bit: props should not be updated inside component
this._onChangeUser = this._onChangeUser.bind(this);
this._onChangeStore = this._onChangeStore.bind(this);
}
componentDidMount() {
CodeStore.addChangeListener(this._onChange); // this is OK
}
_onChangeUser(event) {
console.log('EVENT!');
var enteredChars = event.target.value;
CodeService.nextCode(enteredChars);
// No need to update state here - go to sleep until store changes
}
_onChangeStore() {
var newList = getListFromStore(); // your own function to get list from store
this.setState({ options: newList}); // update state here
}
不确定您所说的 'one tick behind' 是什么意思,或者是什么导致了它,但是清理死循环是一个很好的起点 ;)
PS: 以上代码仅为草图,可能有错别字。
我使用 onChange
触发了对 elasticsearch 的 API 调用,以便我可以提示自动完成列表。
为了确保我的商店在重新渲染之前得到更新,我添加了 componentDidMount 这样我就不会落后一个滴答声。但是进入正题需要代码,所以:
constructor(props) {
super(props)
this.state = {
inputValue: '',
options: []
};
this.props = {
inputValue: '',
options: []
};
this._onChange = this._onChange.bind(this);
}
componentDidMount() {
CodeStore.addChangeListener(this._onChange);
}
_onChange(event) {
if (this.state.inputValue && !event) {
var enteredChars = this.state.inputValue;
console.log('NO EVENT!');
} else if (event.target.value) {
console.log('EVENT!');
var enteredChars = event.target.value;
this.setState({inputValue: enteredChars});
}
CodeService.nextCode(enteredChars);
}
如您所见,我添加了一些日志事件只是为了确保我的情况正常。我读到 setState
引发重新渲染,因此它在条件内,但并未停止循环。并且控制台日志确认条件切换。但是在我的条件中包含 setState
会阻止功能,我没有得到列表。
这是我的日志:
0
Home.jsx:48 EVENT!
Home.jsx:50 0
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
10OptionTemplate.jsx:15 render-list
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
10OptionTemplate.jsx:15 render-list
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
无限循环无论如何都不会影响性能。我认为是因为 componentWillUnmount
但必须避免大量 API 调用。希望这些信息足以提供任何证据。
您的输入事件和存储侦听器似乎都在使用 _onChange。他们需要不同的方法。
看起来无限循环是由以下模式引起的:
- 用户类型输入
- _onChange 更新状态 + 触发存储操作
- 商店自行更新并发送更改事件
- 商店更改事件触发 相同 _onChange 事件
- _onChange 不更新状态,但仍然触发存储操作
- 转到第 3 步并重复(无限期)
修复步骤:
- 为用户输入和商店更新制作不同的更改处理程序(正如@Janaka Stevens 已经建议的那样)
- 将存储中的数据放入状态
- 用户输入不必处于状态(如果您的 React 代码未向输入字段提供值,它将以空值开头,并保留任何键入的内容)
那么您的代码可能如下所示:
constructor(props) {
super(props)
this.state = {
options: []
};
// removed the this.props bit: props should not be updated inside component
this._onChangeUser = this._onChangeUser.bind(this);
this._onChangeStore = this._onChangeStore.bind(this);
}
componentDidMount() {
CodeStore.addChangeListener(this._onChange); // this is OK
}
_onChangeUser(event) {
console.log('EVENT!');
var enteredChars = event.target.value;
CodeService.nextCode(enteredChars);
// No need to update state here - go to sleep until store changes
}
_onChangeStore() {
var newList = getListFromStore(); // your own function to get list from store
this.setState({ options: newList}); // update state here
}
不确定您所说的 'one tick behind' 是什么意思,或者是什么导致了它,但是清理死循环是一个很好的起点 ;)
PS: 以上代码仅为草图,可能有错别字。