programing

응답 입력 onChange 지연

padding 2023. 4. 3. 21:20
반응형

응답 입력 onChange 지연

간단한 제어 입력이 있습니다.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))

크롬의 react devtools에서 상태 업데이트를 보고 있는데, 입력되는 문자와 상태 업데이트 사이에 최소 500ms의 차이가 있으며, 더 빠른 입력을 위해 훨씬 더 오래 걸립니다.setState가 이렇게 느린 이유는 무엇입니까?이 양식이 일반 웹 양식처럼 작동하도록 하려면 어떻게 해야 합니까?

setState그 자체는 느리지 않습니다.렌더가 매우 비싸질 때만 문제가 생기기 시작합니다.

고려해야 할 사항은 다음과 같습니다.

  • 메인 컴포넌트는 매우 큰 것 같아서 키를 누를 때마다 다시 렌더링되므로 성능 문제가 발생할 수 있습니다.더 작은 컴포넌트로 나누어 보겠습니다.
  • 합니다.render메인 컴포넌트의 메서드는 불필요하게 재평가되지 않습니다.React Developer Tools 또는 Why-do-You-render는 이러한 불필요한 리렌더를 지적할 수 있습니다.로의 전환PureComponent상태 비저장 컴포넌트 또는 should Component Update를 사용하면 도움이 됩니다.
  • 양식 입력이 새 상태 값으로 다시 렌더링되어야 하므로 여기서 재렌더링을 피할 수는 없지만, 더 작은 구성 요소로 나누면 wakeComponentUpdate를 사용하여 구성 요소의 출력이 현재 상태 또는 소품 변경의 영향을 받지 않는지 여부를 React에 알리고 불필요한 재렌더링을 방지할 수 있습니다.
  • 「 」 「 」 、 「 」
    • 종속성이 변경되지 않는 한 값비싼 작업 또는 구성 요소를 다시 계산하지 않으려면 useMemo를 사용하십시오.
    • useCallback을 사용하여 메모된 콜백 버전을 반환하여 참조 동등성에 의존하는 하위 구성 요소가 불필요하게 다시 렌더링되지 않도록 합니다.
    • 기능 컴포넌트가 같은 소품으로 같은 결과를 렌더링하는 경우 React.memo를 사용하여 불필요한 재렌더링을 방지합니다.두 번째 인수를 사용하여React.memo(메모화의 동작은, 「메모화」와 ).shouldComponentUpdate)
  • 성능 향상을 위해 프로덕션 빌드로 전환
  • 제어되지 않는 컴포넌트로 전환하여 입력 컴포넌트 자체를 DOM이 처리하도록 합니다(이것은, 설명한 「통상적인 Web 폼」동작입니다).양식 값에 액세스해야 할 때 사용할 수 있습니다.ref기본 DOM 노드에 액세스하여 해당 노드에서 직접 값을 읽어냅니다. 하면, 굳이 전화할 .setState 렌더(렌더)가 됩니다.

여기에는 redux가 간섭하지 않는 것처럼 보이지만, 이는 특히 하나의 입력이 변경되면 컴포넌트 전체가 재렌더되고 redux가 재렌더되는 큰 형태에서 문제가 됩니다.

입력을 제어하고 정확한 동작을 유지하려면 항상 이렇게 할 수 있습니다.

<input
  className="form-control"
  type="text"
  name="name"
  value={form.name}
  onBlur={onChangeHandler}
/>

이로 인해 블러시에만 이벤트가 트리거되고 변경 시마다 재렌더가 방지됩니다.데이터를 처리하기 위해 다른 버튼을 클릭하면 업데이트된 상태가 보장되므로 유용합니다.로직에서 입력 데이터와 관련된 즉각적인 검증/처리가 필요한 경우 이 방법은 도움이 되지 않습니다.

또한 HTML5가 네이티브가 아닌 다른 컴포넌트에서는 이 컴포넌트가 동작하지 않을 수 있습니다.이는 가치관에 근거한 재렌더를 방해할 수 있기 때문입니다.

참고: OnBlur 이벤트를 읽어보십시오.

간단한 응답처럼 보일 수 있지만 콘솔이 닫혀 있는지 확인하십시오.콘솔이 열려 있을 때 제어된 컴포넌트에서 현저한 지연이 발생합니다.

빅 하는 경우에서 모든 합니다.debounce을 사용하다

Options given by @ᴘᴀɴᴀʏɪᴏᴛɪs are good but for my use case it didn't help.상태를 설정하기 전에 데바운스를 추가하여 해결했습니다.

const delaySetStateWithDelay = () => {
    if (lastRequest) {
      window.clearTimeout(lastRequest);
    }
    lastRequest = setTimeout(() => {
      setStateData('Data I Need To Set'
    }, 500);
  };

https://reactjs.org/docs/perf.html을 사용하여 앱을 프로파일링할 수 있습니다.재렌더될 가능성이 있는 컴포넌트가 다수 있습니까?몇 가지 추가가 필요할 수 있습니다.componentShouldUpdate()불필요한 재접속을 방지하기 위한 방법을 제공합니다.

최근에도 같은 문제에 직면했습니다.리덕스 스토어와 그 안에 설명이 있었습니다.스토어 입력의 모든 키 스트로크를 갱신해야 했기 때문에, 그 후, 나는 디버깅을 하려고 했습니다.lodash근데 그게 안 돼서 타임아웃 설정 기능을 만들어서 이렇게 스토어 상태를 업데이트 하고

 setTimeout(() => {
  console.log("setting");
  this.props.addDescription(this.state.description);
}, 200);

의 자체 마다 설명 입력 필드 값을 합니다.componentDidMount()스토어에서 최신 업데이트 설명 값을 가져옵니다.

개발 모드의 느린 입력에도 비슷한 문제가 있었지만, 기능적인 컴포넌트와 후크는 문제가 있었습니다.실전 가동은 괜찮았지만, 확실히 프로덕션을 켜는 것은 어프로치로 보이지 않습니다.개발 모드에서 속도가 너무 느리면 코드에 문제가 있을 가능성이 높습니다.그래서 해결책은 나머지 컴포넌트에서 입력 상태를 분리하는 것이었습니다.구성 요소에서 사용되는 상태는 이 구성 요소에 대해서만 사용할 수 있어야 합니다.사실 그것은 해결책이 아니라 어떻게 반응해야 하는가 하는 것입니다.

얼마 전에도 같은 문제가 발생하여 부모 컴포넌트에서 로컬 오브젝트로 상태를 복사한 후 새로운 로컬 오브젝트를 제 입력에 참조해야 했습니다.

양식을 저장하기 전에 다른 곳에서 새로운 상태를 사용할 필요가 없다면 아래의 솔루션을 사용할 수 있을 것입니다.

  const { selectedCustomer } = props;
  const [localCustomer, setLocalCustomer] = useState({ name: 'Default' });

  useEffect(() => {
    setLocalCustomer({ ...selectedCustomer });
  }, [selectedCustomer]);

  const handleChangeName = (e) => {
    setLocalCustomer({ ...localCustomer, name: e.target.value });
  };

내 텍스트 필드에 사용할 수 있습니다.

<StyledTextField
 fullWidth
 type='text'
 label='Name'
 value={localCustomer.name}
</StyledTextField>

빠른 set Timeout을 추가하는 것만으로 퍼포먼스가 크게 향상되었습니다.100ms 이상의 타임아웃에 대해 우려했던 것은 실장에 따라서는 setState 데이터가 아직 추가되지 않았을 수 있다는 것입니다.다음과 같은 방법으로 실제 상황에서 이러한 일이 발생하지 않도록 해야 합니다.

const onChange = (mydata) => setTimeout(() => setState(mydata), 10);

위의 @Sudhanshu Kumar의 투고에서 알 수 있듯이 입력 요소가 콜백으로 변경 핸들러를 전달함으로써 포커스를 잃었을 때 setState 콜을 실행하기 위해 'onBlur'를 사용할 수 있습니다.이 기능을 MUI와 함께 사용하려면 다음을 사용하십시오.

<TextField
   ...props
   inputProps={{
     onBlur: handleChange
   }}
/>

이를 통해 네이티브브라우저 onBlur 메서드를 덮어쓸 수 있습니다.이게 도움이 됐으면 좋겠다.

언급URL : https://stackoverflow.com/questions/50819260/react-input-onchange-lag

반응형