首页 文章

响应输入onChange滞后

提问于
浏览
0

我有一个带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 回答

  • 0

    setState 本身并不慢,只有当你的渲染变得非常昂贵时才开始引起问题 .

    需要考虑的一些事项是:

    • 您的主要组件看起来非常大,并且在每次击键时都会重新渲染,因此可能会导致性能问题 . 尝试将其分解为更小的组件 .

    • 确保在主组件的 render 方法中呈现的子组件不会被不必要地重新呈现 . why-did-you-update可以指出那些不必要的重新渲染 . 切换到 PureComponent ,无状态组件或使用shouldComponentUpdate可以提供帮助 .

    • 虽然你不能避免在这里重新渲染(因为你的表单输入需要用新的状态值重新渲染),通过分解成更小的组件,你可以使用shouldComponentUpdate让React知道组件的输出是否不受当前变化的影响在州或道具,避免不必要的重新渲染 .

    • 切换到 生产环境 版本以获得更好的性能

    • 切换到uncontrolled components并让DOM自己处理输入组件(这是您描述的"normal web form"行为) . 当您需要访问表单的值时,您可以使用 ref 来访问底层DOM节点并直接从中读取值 . 这样就不需要调用 setState ,因此需要重新渲染

  • 4

    您可以使用https://reactjs.org/docs/perf.html来分析您的应用 . 您是否有大量可以重新渲染的组件?可能需要向组件添加一些 componentShouldUpdate() 方法以防止无用的重新渲染 .

相关问题