매초마다 React 컴포넌트 업데이트


114

나는 React를 가지고 놀았고 Date.now()화면에 렌더링되는 다음과 같은 시간 구성 요소를 가지고 있습니다.

import React, { Component } from 'react';

class TimeComponent extends Component {
  constructor(props){
    super(props);
    this.state = { time: Date.now() };
  }
  render(){
    return(
      <div> { this.state.time } </div>
    );
  }
  componentDidMount() {
    console.log("TimeComponent Mounted...")
  }
}

export default TimeComponent;

이 구성 요소를 매초마다 업데이트하여 React 관점에서 시간을 다시 그리는 가장 좋은 방법은 무엇입니까?

답변:


152

를 사용 setInterval하여 변경을 트리거해야하지만 구성 요소가 마운트 해제 될 때 타이머를 지워서 오류를 남기고 메모리 누수를 방지해야합니다.

componentDidMount() {
  this.interval = setInterval(() => this.setState({ time: Date.now() }), 1000);
}
componentWillUnmount() {
  clearInterval(this.interval);
}

2
이런 종류의 것을 캡슐화하는 라이브러리를 원한다면 내가 만들었습니다react-interval-rerender
Andy

생성자에 setInterval 메서드를 추가했는데 더 잘 작동했습니다.
aqteifan 19 년

89

다음 코드는 React.js 웹 사이트에서 수정 된 예제입니다.

원본 코드는 여기에서 확인할 수 있습니다 : https://reactjs.org/#a-simple-component

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      seconds: parseInt(props.startTimeInSeconds, 10) || 0
    };
  }

  tick() {
    this.setState(state => ({
      seconds: state.seconds + 1
    }));
  }

  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  formatTime(secs) {
    let hours   = Math.floor(secs / 3600);
    let minutes = Math.floor(secs / 60) % 60;
    let seconds = secs % 60;
    return [hours, minutes, seconds]
        .map(v => ('' + v).padStart(2, '0'))
        .filter((v,i) => v !== '00' || i > 0)
        .join(':');
  }

  render() {
    return (
      <div>
        Timer: {this.formatTime(this.state.seconds)}
      </div>
    );
  }
}

ReactDOM.render(
  <Timer startTimeInSeconds="300" />,
  document.getElementById('timer-example')
);

1
나는 어떤 이유로 this.updater.enqueueSetState 가이 접근 방식을 사용할 때 함수 오류가 아닙니다. setInterval 콜백은 this 구성 요소에 올바르게 바인딩됩니다.
baldrs

16
나 같은 바보를 들어 : 타이머의 이름을 지정하지 않는 것은 updater이 업데이트주기 유적 때문에
baldrs

3
ES6를 사용하면 this.interval = setInterval (this.tick.bind (this), 1000);
Kapil

참조하는 URL에 링크를 추가 할 수 있습니까? 감사합니다 ~
frederj

보다 견고 함을 위해 서식 지정 방법과 "생성자"속성을 추가했습니다.
Mr. Polywhirl

15

@Waisky가 제안했습니다.

를 사용 setInterval하여 변경을 트리거해야하지만 구성 요소가 마운트 해제 될 때 타이머를 지워서 오류를 남기고 메모리 누수를 방지해야합니다.

똑같은 일을하고 싶다면 Hooks를 사용하세요 :

const [time, setTime] = useState(Date.now());

useEffect(() => {
  const interval = setInterval(() => setTime(Date.now()), 1000);
  return () => {
    clearInterval(interval);
  };
}, []);

의견에 관하여 :

내부에 아무것도 전달할 필요가 없습니다 []. time대괄호 를 전달하면 time변경 값이 변경 될 때마다 효과가 실행된다는 의미입니다 . 즉 setInterval, time변경 될 때마다 새 효과를 호출합니다. 이는 우리가 찾고있는 것이 아닙니다. 우리는 호출 할 setInterval구성 요소가 설치됩니다 때 일단 다음 setInterval호출 setTime(Date.now())1,000 초. 마지막으로 clearInterval컴포넌트가 마운트 해제 될 때 호출 합니다.

구성 요소는 time값이 time변경 될 때마다 사용한 방식에 따라 업데이트 됩니다. 즉 퍼팅과는 아무 상관이 없습니다 time[]의를 useEffect.


1
[]두 번째 인수로 빈 배열 ( ) 을 전달한 이유는 무엇 useEffect입니까?
Mekeor Melire

효과 후크에 문서 반응 저희에게 말한다 : "당신이, 두 번째 인수로 빈 배열 ([]) 전달할 수있는 효과를 실행하고 (마운트 및 마운트 해제에) 한 번만을 정리합니다." 그러나 OP는 효과가 매초마다, 즉 한 번만이 아니라 반복되기를 원합니다.
Mekeor Melire

배열에서 [time]을 전달하면 간격마다 구성 요소가 생성되고 파괴됩니다. 빈 배열 []을 전달하면 구성 요소를 계속 새로 고치고 페이지를 떠날 때만 마운트 해제합니다. 하지만 두 경우 모두 제대로 작동하려면 key = {time} 또는 key = {Date.now ()}를 추가하여 실제로 다시 렌더링해야했습니다.
Teebu

8

구성 요소의 componentDidMount수명주기 메서드에서 상태를 업데이트하는 함수를 호출하는 간격을 설정할 수 있습니다.

 componentDidMount() {
      setInterval(() => this.setState({ time: Date.now()}), 1000)
 }

4
정답이지만 최고의 답변에서 알 수 있듯이 메모리 누수를 방지하려면 시간을 지워야합니다. componentWillUnmount () {clearInterval (this.interval); }
Alexander Falk

3
class ShowDateTime extends React.Component {
   constructor() {
      super();
      this.state = {
        curTime : null
      }
    }
    componentDidMount() {
      setInterval( () => {
        this.setState({
          curTime : new Date().toLocaleString()
        })
      },1000)
    }
   render() {
        return(
          <div>
            <h2>{this.state.curTime}</h2>
          </div>
        );
      }
    }

0

그래서 당신은 올바른 길을 가고있었습니다. 내부 에서 변경을 트리거하도록 componentDidMount()구현하여 작업을 완료 할 수 setInterval()있지만 구성 요소 상태를 업데이트하는 방법은를 통해 수행하는 setState()것이므로 내부에서 다음 componentDidMount()을 수행 할 수 있습니다.

componentDidMount() {
  setInterval(() => {
   this.setState({time: Date.now()})    
  }, 1000)
}

또한 위에서 제공 한 구현으로 Date.now()작동하는 것을 사용 componentDidMount()하지만 사람이 읽을 수없는 긴 숫자 업데이트를 얻을 수 있지만 기술적으로는 1970 년 1 월 1 일 이후 밀리 초 단위로 매초 업데이트되는 시간입니다. 그래서 학습 및 구현하는 것 외에, 우리는 읽기 시간을 인간이 어떻게이 시간을 읽을 수 있도록하려는 setInterval당신에 대해 배우고 싶어 new Date()하고 toLocaleTimeString()당신은 너무 좋아 구현하는 것입니다 :

class TimeComponent extends Component {
  state = { time: new Date().toLocaleTimeString() };
}

componentDidMount() {
  setInterval(() => {
   this.setState({ time: new Date().toLocaleTimeString() })    
  }, 1000)
}

constructor()함수를 제거 했는데 꼭 필요한 것은 아닙니다. 리팩터링은 constructor()함수로 사이트를 초기화하는 것과 100 % 동일 합니다.


0

componentWillReceiveProps ()가 더 이상 사용되지 않는 React V16의 변경으로 인해 구성 요소를 업데이트하는 데 사용하는 방법론입니다. 아래 예제는 Typescript에 있으며 정적 getDerivedStateFromProps 메서드를 사용하여 Prop이 업데이트 될 때마다 초기 상태와 업데이트 된 상태를 가져옵니다.

    class SomeClass extends React.Component<Props, State> {
  static getDerivedStateFromProps(nextProps: Readonly<Props>): Partial<State> | null {
    return {
      time: nextProps.time
    };
  }

  timerInterval: any;

  componentDidMount() {
    this.timerInterval = setInterval(this.tick.bind(this), 1000);
  }

  tick() {
    this.setState({ time: this.props.time });
  }

  componentWillUnmount() {
    clearInterval(this.timerInterval);
  }

  render() {
    return <div>{this.state.time}</div>;
  }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.