我有一个带onChange事件处理程序的简单控制输入 . 一切正常,每次击键都会触发handleChange,问题是它很慢 . 使用输入时存在非常明显的延迟 . 是否有一些额外的代码我必须正常工作才能正常输入?我是否必须去除输入?据我所知,在文档中没有提到这个问题,我不需要做一些额外的事情,或者我正在使用onChange回调错误 .
handleChange = (event) => {
this.setState({ itemNumber: event.target.value })
}
<TextField
id="Part #"
label="Part #"
value={this.state.itemNumber}
onChange={this.handleChange}
margin="normal"
/>
组件:
export class Dashboard extends Component {
state = {
report: '',
selectedDate: new Date(),
itemNumber: '',
}
static propTypes = {
classes: object,
headerTitle: string,
userInfo: object,
}
static defaultProps = {
classes: {},
headerTitle: undefined,
userInfo: {},
}
reportSelected = (event) => {
this.setState(() => {
return {
report: event.target.value,
}
})
}
handleDateChange = (date) => {
this.setState({ selectedDate: new Date(date) })
}
handleChange = (event) => {
this.setState({ itemNumber: event.target.value })
}
render () {
const { classes, headerTitle, userInfo } = this.props
return (
<div className={classes.dashboard}>
<HeaderTitle title="Dashboard" />
<Helmet>
<title>{headerTitle}</title>
</Helmet>
{ userInfo.isAuthorized &&
<Grid container direction={'row'} justify={'center'} className={classes.formContainer}>
<Grid item xs={12} sm={12} md={12} lg={6} xl={5}>
<form className={classes.form}>
<FormControl className={classes.presetReportsInput}>
<InputLabel htmlFor="reports">Preset Reports</InputLabel>
<Select
value={this.state.report}
onChange={this.reportSelected}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{presetReports.getReportList().map(report => (
<MenuItem value={report.name} key={report.name}>
{report.name}
</MenuItem>
))}
</Select>
</FormControl>
{ (this.state.report === 'Inventory Snapshot' ||
this.state.report === 'Weekly Fill Rate' ||
this.state.report === 'Open Orders' ||
this.state.report === 'Weekly Shipments') &&
<div>
<Grid container spacing={8} direction={'row'}>
<Grid item>
<MuiPickersUtilsProvider utils={MomentUtils}>
<DatePicker
className={classes.datePicker}
margin="normal"
keyboard
format="DD/MM/YYYY"
disableFuture
autoOk
mask={value => (value ? [/\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/] : [])}
value={this.state.selectedDate}
onChange={this.handleDateChange}
disableOpenOnEnter
animateYearScrolling={false}
/>
</MuiPickersUtilsProvider>
</Grid>
<Grid item>
<TextField
id="Part #"
label="Part #"
value={this.state.itemNumber}
onChange={this.handleChange}
margin="normal"
/>
</Grid>
</Grid>
<Button variant="raised" color="primary" style={{ marginTop: 10 }}>
Search
</Button>
</div>
}
{ this.state.report === '' &&
<div>
<TextField
id="queryField"
label="Run a Query"
className={classes.queryField}
helperText=""
margin="normal"
multiline
rows="5"
/>
<Grid container direction={'row'} justify={'flex-end'}>
<Grid item>
<Button variant="raised" color="primary">
Export
</Button>
</Grid>
<Grid item>
<Button variant="raised" color="primary">
Save Query
</Button>
</Grid>
</Grid>
</div>
}
</form>
</Grid>
{ this.state.report === 'Inventory Snapshot' &&
<Grid container className={classes.table}>
<Grid item xs={12} sm={12} md={12} lg={12} xl={12}>
<InventoryReport />
</Grid>
</Grid>
}
</Grid>
}
</div>
)
}
}
const styles = {
dashboard: {},
formContainer: {
margin: 0,
width: '100%',
},
presetReportsInput: {
width: '100%',
margin: '20% 0 0 0',
},
queryField: {
width: '100%',
margin: '20% 0 0 0',
},
table: {
margin: '50px 0 10px 0',
},
datePicker: {
marginTop: 32,
},
}
const mapStateToProps = state => {
const { layout } = state
const { headerTitle } = layout
return {
headerTitle: headerTitle,
}
}
export default connect(mapStateToProps)(withStyles(styles)(Dashboard))
我正在观看chrome中的devtools的状态更新,并且输入的字符和状态更新之间至少有500毫秒的延迟,更快的打字速度要长得多 . 为什么setState这么慢?使此表单行为像普通Web表单一样的解决方法是什么?
2 回答
setState
本身并不慢,只有当你的渲染变得非常昂贵时才开始引起问题 .需要考虑的一些事项是:
您的主要组件看起来非常大,并且在每次击键时都会重新渲染,因此可能会导致性能问题 . 尝试将其分解为更小的组件 .
确保在主组件的
render
方法中呈现的子组件不会被不必要地重新呈现 . why-did-you-update可以指出那些不必要的重新渲染 . 切换到PureComponent
,无状态组件或使用shouldComponentUpdate可以提供帮助 .虽然你不能避免在这里重新渲染(因为你的表单输入需要用新的状态值重新渲染),通过分解成更小的组件,你可以使用shouldComponentUpdate让React知道组件的输出是否不受当前变化的影响在州或道具,避免不必要的重新渲染 .
切换到 生产环境 版本以获得更好的性能
切换到uncontrolled components并让DOM自己处理输入组件(这是您描述的"normal web form"行为) . 当您需要访问表单的值时,您可以使用
ref
来访问底层DOM节点并直接从中读取值 . 这样就不需要调用setState
,因此需要重新渲染您可以使用https://reactjs.org/docs/perf.html来分析您的应用 . 您是否有大量可以重新渲染的组件?可能需要向组件添加一些
componentShouldUpdate()
方法以防止无用的重新渲染 .