我正在研究别人编写的现有React代码,并且面临一些性能问题。考虑以下代码片段:
//ComponentA.js
class ComponentA extends React.Component {
this.state = { someValue : 'dummy' }
// Other code
// We are using Babel, so class fields are OK
updateVal = e => this.setState({ someValue : e.target.value})
// fetchData makes an ajax call
fetchData = () => { fetch(this.state.someValue) }
render() {
return (
<ComponentB val={this.state.someValue}
updateVal={this.updateVal}
fetchData={this.fetchData}/>
)
}
//ComponentB.js
class ComponentB extends React.Component {
render() {
return (
// Other code
//Input is a component from a library
<Input onChange={(e) => { this.updateValue(e) } }
onBlur={this.props.fetchData} />
value={this.props.val}
)
}
}
现在的问题是,每当用户键入Input
时,几秒钟后就会显示该值。这是因为ComponentA实际上是一个很大的组件(我知道它很糟糕,但是由于它很大而且我们没有太多时间,所以我现在不想对其进行重构),并且每次用户输入时都会重新渲染它。为避免这种情况,我可以使Input
成为不受控制的组件,并更新ComponentA
的{{1}} someValue
。另一种方法是在onBlur
中有一个initialState
,它等于ComponentB
道具。并且val
,onChange
仅用于this.setState
。然后ComponentB
,我可以更新onBlur
的{{1}}。
但是,在这两种方法中,React的ComponentA
原理都丢失了。那么在这种情况下最好的解决方案是什么?
在这里我还要问,在这里使用不受控制的组件有什么害处?
答案 0 :(得分:0)
一个快速解决方案可能是对onChange
处理程序进行反跳。
我通常使用Lodash的debounce
,但您可以使用另一个版本,也可以编写自己的版本。
import { debounce } from 'lodash'
class ComponentB extends React.Component {
// componentA will rerender only every 300ms instead of every time user types
handleChange = debounce(e => this.props.updateVal(e), 300)
render() {
return <Input onChange={this.handleChange} value={this.props.val} />
}
}
最好的解决方案是拆分/重构componentA
。
答案 1 :(得分:0)
重新渲染进行了优化(我认为问题不在于组件尺寸)。 我认为问题不是由您的结构(这是React本身建议的)引起的,而是由库中的Input组件引起的。
您还可以将状态保留在ComponentB中并公开函数以获取/设置值,但是,正如您所说的那样,您将丢失single source of trouth
,但是将避免重新呈现每个输入更改。
希望这会有所帮助!