>  기사  >  웹 프론트엔드  >  React.setState를 사용할 때 주의해야 할 점은 무엇인가요?

React.setState를 사용할 때 주의해야 할 점은 무엇인가요?

亚连
亚连원래의
2018-06-20 11:17:551754검색

이 글에서는 React.setState를 사용할 때 주의해야 할 세 가지 사항을 주로 소개합니다. 관심 있는 친구들이 참고할 수 있는 세 가지 사항을 제시합니다. 서문

이 기사의 원래 제목은 내가 React.setState 사용을 중단한 3가지 이유입니다. 그러나 나는 원저자가 제시한 주장에는 별로 관심이 없지만, 저자가 제기한 세 가지 요점은 무시하기 쉽습니다. React 초보자를 위한 부분이므로 여기에는 내용의 일부만 전하고, React.setState를 사용할 때 주의해야 할 세 가지 사항으로 제목을 변경했습니다.

Text

React 초보자에게 setState를 사용하는 것은 매우 복잡한 일입니다. React 개발에 숙련된 사람이라도 다음 예와 같이 React의 일부 메커니즘으로 인해 버그가 있을 수 있습니다.

이 문서에서는 setState를 사용할 때 주의해야 할 문제에 대해서도 설명합니다.

참고:

나중에 setState()를 호출하면 변경한 내용이 대체될 수 있으므로 this.state를 직접 변경하지 마세요

. this.state를 불변으로 취급하십시오.

setState()는 this.state를 즉시 변경하지 않지만 곧 처리될 상태 전환을 생성합니다. 이 메서드를 호출한 후 this.state에 액세스하면 기존 값이 반환될 수 있습니다.

setState 호출에는 동기화가 보장되지 않으며 성능 향상을 위해 호출을 일괄 처리할 수 있습니다.

setState()는 shouldComponentUpdate()에서 조건부 렌더링 로직이 구현되지 않는 한 항상 다시 그리기를 트리거합니다. 가변 객체가 사용되고 이 로직을 shouldComponentUpdate()에서 구현할 수 없는 경우 새 상태와 이전 상태 사이에 차이가 있을 때만 setState()를 호출하면 불필요한 재렌더링을 피할 수 있습니다.

결론적으로 setState를 사용할 때 주의해야 할 세 가지 문제가 있습니다.

1. setState는 비동기입니다(번역자 주: 동기화가 보장되지 않음)

많은 개발자는 처음에 setState가 비동기라는 사실을 알아차리지 못했습니다. . 일부 상태를 수정한 후 직접 보면 이전 상태가 표시됩니다. 이것은 setState에서 가장 오류가 발생하기 쉬운 곳입니다. setState라는 단어는 비동기적으로 보이지 않으므로 아무 생각 없이 사용하면 버그가 발생할 수 있습니다. 다음 예는 이 문제를 잘 보여줍니다.

class Select extends React.Component {
 constructor(props, context) {
  super(props, context)
  this.state = {
   selection: props.values[0]
  };
 }
 
 render() {
  return (
   <ul onKeyDown={this.onKeyDown} tabIndex={0}>
    {this.props.values.map(value =>
     <li
      className={value === this.state.selection ? &#39;selected&#39; : &#39;&#39;}
      key={value}
      onClick={() => this.onSelect(value)}
     >
      {value}
     </li> 
    )} 
   </ul>
  )
 }
 
 onSelect(value) {
  this.setState({
   selection: value
  })
  this.fireOnSelect()
 }

 onKeyDown = (e) => {
  const {values} = this.props
  const idx = values.indexOf(this.state.selection)
  if (e.keyCode === 38 && idx > 0) { /* up */
   this.setState({
    selection: values[idx - 1]
   })
  } else if (e.keyCode === 40 && idx < values.length -1) { /* down */
   this.setState({
    selection: values[idx + 1]
   }) 
  }
  this.fireOnSelect()
 }
  
 fireOnSelect() {
  if (typeof this.props.onSelect === "function")
   this.props.onSelect(this.state.selection) /* not what you expected..*/
 }
}

ReactDOM.render(
 <Select 
  values={["State.", "Should.", "Be.", "Synchronous."]} 
  onSelect={value => console.log(value)}
 />,
 document.getElementById("app")
)

얼핏 보면 이 코드에는 아무런 문제가 없어 보입니다. onSelect 메소드는 두 이벤트 핸들러 모두에서 호출됩니다. 그러나 Select 구성 요소에는 이전 GIF를 잘 보여주는 버그가 있습니다. onSelect 메소드는 항상 이전 state.selection 값을 전달합니다. 왜냐하면 fireOnSelect가 호출될 때 setState가 아직 작업을 완료하지 않았기 때문입니다. 저는 React가 최소한 setState를 ScheduleState로 변경하거나 콜백 함수를 필수 매개변수로 만들어야 한다고 생각합니다.

이 버그는 수정하기 쉽습니다. 가장 어려운 부분은 이 문제가 있다는 것을 알아야 한다는 것입니다.

2. setState는 불필요한 렌더링을 발생시킵니다

setState로 인해 발생하는 두 번째 문제는 모든 호출이 다시 렌더링된다는 것입니다. 많은 경우 이러한 재렌더링은 불필요합니다. React 성능 도구에서 printWasted를 사용하여 불필요한 렌더링이 발생하는지 확인할 수 있습니다. 그러나 대략적으로 말하면 불필요한 렌더링에는 여러 가지 이유가 있습니다.

새 상태는 실제로 이전 상태와 동일합니다. 이 문제는 일반적으로 shouldComponentUpdate로 해결될 수 있습니다. 이 문제를 해결하기 위해 순수 렌더링이나 다른 라이브러리를 사용할 수도 있습니다.
  1. 일반적으로 변경된 상태는 렌더링과 관련이 있지만 예외도 있습니다. 예를 들어 일부 데이터는 특정 상태를 기반으로 표시됩니다.
  2. 셋째, 일부 상태는 렌더링과 관련이 없습니다. 일부 상태는 이벤트 및 타이머 ID와 관련될 수 있습니다.
  3. 3.setState는 모든 구성 요소 상태를 매우 효과적으로 관리할 수 없습니다.

위의 마지막 점에 따르면 모든 구성 요소 상태를 setState로 저장하고 업데이트해서는 안 됩니다. 복잡한 구성 요소에는 관리해야 하는 다양한 상태가 있을 수 있습니다. 이러한 상태를 관리하기 위해 setState를 사용하면 불필요한 재렌더링이 많이 발생할 뿐만 아니라 관련 수명 주기 후크가 항상 호출되어 많은 이상한 문제가 발생합니다.

나중에는

원문에서 저자가 몇몇 상태를 관리하기 위해 MobX라는 라이브러리를 추천했다고 해서 별로 춥지 않아서 소개하지 않겠습니다. 관심이 있으신 분은 상단 링크를 통해 원문의 소개를 읽어보실 수 있습니다.

위에서 제기한 세 가지 사항을 토대로 초보자들은 다음 사항에 주의해야 한다고 생각합니다.

setState는 동기화를 보장하지 않습니다.

setState는 동기화를 보장하지 않습니다., 동기화를 보장하지 않습니다, 동기화를 보장하지 않습니다. 동기화됩니다. 중요한 말을 세 번 말하세요. 비동기식이라고 하지 않는 이유는 setState도 어떤 경우에는 동기식으로 업데이트되기 때문입니다. 이 글을 참고하세요

setState 직후에 수정된 값을 가져와야 하는 경우 다음과 같은 몇 가지 옵션이 있습니다.

해당 매개변수를 전달하고 this.state를 통해 가져오지 마세요

针对于之前的例子,完全可以在调用 fireOnSelect 的时候,传入需要的值。而不是在方法中在通过 this.state 来获取

使用回调函数

setState 方法接收一个 function 作为回调函数。这个回掉函数会在 setState 完成以后直接调用,这样就可以获取最新的 state 。对于之前的例子,就可以这样:

this.setState({
 selection: value
}, this.fireOnSelect)

使用setTimeout

在 setState 使用 setTimeout 来让 setState 先完成以后再执行里面内容。这样子:

this.setState({
 selection: value
});
setTimeout(this.fireOnSelect, 0);

直接输出,回调函数, setTimeout 对比

componentDidMount(){
  this.setState({val: this.state.val + 1}, ()=>{
   console.log("In callback " + this.state.val);
  });

  console.log("Direct call " + this.state.val);  
  setTimeout(()=>{
   console.log("begin of setTimeout" + this.state.val);
    this.setState({val: this.state.val + 1}, ()=>{
     console.log("setTimeout setState callback " + this.state.val);
    });

   setTimeout(()=>{
    console.log("setTimeout of settimeout " + this.state.val);
   }, 0);

   console.log("end of setTimeout " + this.state.val);
  }, 0);
 }

如果val默认为0, 输入的结果是:

Direct call 0
In callback 1
begin of setTimeout 1
setTimeout setState callback 2
end of setTimeout 2
setTimeout of settimeout 2

和渲染无关的状态尽量不要放在 state 中来管理

通常 state 中只来管理和渲染有关的状态 ,从而保证 setState 改变的状态都是和渲染有关的状态。这样子就可以避免不必要的重复渲染。其他和渲染无关的状态,可以直接以属性的形式保存在组件中,在需要的时候调用和改变,不会造成渲染。

避免不必要的修改,当 state 的值没有发生改变的时候,尽量不要使用 setState 。虽然 shouldComponentUpdate 和 PureComponent 可以避免不必要的重复渲染,但是还是增加了一层 shallowEqual 的调用,造成多余的浪费。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue中使用axios实现文件上传

使用gulp如何创建完整的项目流程

在js中如何实现将数组添加到对象中

在jQuery中如何实现动态控制页面元素

在canvas中如何实现轨迹回放功能

위 내용은 React.setState를 사용할 때 주의해야 할 점은 무엇인가요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.