React 앱의 setInterval


103

나는 여전히 React에서 상당히 새롭지 만 천천히 진행하면서 내가 붙어있는 무언가를 만났습니다.

저는 React에서 "타이머"구성 요소를 구축하려고합니다. 솔직히 말해서 제가이 작업을 올바르게 수행하고 있는지 (또는 효율적으로) 수행하고 있는지 모르겠습니다. 아래에있는 내 코드에서, 나는 개체를 반환 상태를 설정 { currentCount: 10 }하고 놀겠다는 거를하고있다 componentDidMount, componentWillUnmount그리고 render나는 10에서 9 "카운트 다운"의 상태를 얻을 수 있습니다.

두 부분으로 구성된 질문 : 내가 잘못한 것은 무엇입니까? 그리고 ( componentDidMount&를 사용하는 대신) setTimeout을 사용하는 더 효율적인 방법이 componentWillUnmount있습니까?

미리 감사드립니다.

import React from 'react';

var Clock = React.createClass({

  getInitialState: function() {
    return { currentCount: 10 };
  },

  componentDidMount: function() {
    this.countdown = setInterval(this.timer, 1000);
  },

  componentWillUnmount: function() {
    clearInterval(this.countdown);
  },

  timer: function() {
    this.setState({ currentCount: 10 });
  },

  render: function() {
    var displayCount = this.state.currentCount--;
    return (
      <section>
        {displayCount}
      </section>
    );
  }

});

module.exports = Clock;

2
bind(this)더 이상 필요하지 않습니다. 리 액트는 지금이 작업을 자체적으로 수행합니다.
데릭 폴라드

2
당신의 타이머 방법를 currentCount 업데이트하지 않습니다
브라이언 첸

1
@ 데릭 확실해? 난 그냥 내 추가하여 작업있어 this.timer.bind(this)그 자체에 this.timer으로 작동하지 않았다

6
@Theworm @Derek이 잘못되었습니다. React.createClass (더 이상 사용되지 않음)는 메서드를 class Clock extends Component자동 바인딩 하지만 자동 바인딩은하지 않습니다. 따라서 바인딩이 필요한지 여부는 구성 요소를 만드는 방법에 따라 다릅니다.
CallMeNorm

답변:


160

코드에 4 가지 문제가 있습니다.

  • 타이머 방법에서는 항상 현재 카운트를 10으로 설정합니다.
  • 렌더링 메서드에서 상태를 업데이트하려고합니다.
  • setState실제로 상태를 변경하는 방법을 사용하지 않습니다.
  • 상태에 intervalId를 저장하지 않습니다.

이 문제를 해결해 보겠습니다.

componentDidMount: function() {
   var intervalId = setInterval(this.timer, 1000);
   // store intervalId in the state so it can be accessed later:
   this.setState({intervalId: intervalId});
},

componentWillUnmount: function() {
   // use intervalId from the state to clear the interval
   clearInterval(this.state.intervalId);
},

timer: function() {
   // setState method is used to update the state
   this.setState({ currentCount: this.state.currentCount -1 });
},

render: function() {
    // You do not need to decrease the value here
    return (
      <section>
       {this.state.currentCount}
      </section>
    );
}

이로 인해 타이머가 10에서 -N으로 감소합니다. 타이머를 0으로 낮추려면 약간 수정 된 버전을 사용할 수 있습니다.

timer: function() {
   var newCount = this.state.currentCount - 1;
   if(newCount >= 0) { 
       this.setState({ currentCount: newCount });
   } else {
       clearInterval(this.state.intervalId);
   }
},

감사합니다. 이것은 많은 의미가 있습니다. 저는 여전히 초심자이며 상태가 어떻게 작동하는지 그리고 렌더링과 같은 "덩어리"가 어떻게 진행되는지 파악하려고합니다.
Jose

하지만 실제로 간격을 설정하려면 componentDidMount 및 componentWillUnmount를 사용해야합니까? 편집 : 최근 편집 한 내용을 확인했습니다. :)
Jose

@Jose componentDidMount는 클라이언트 측 이벤트를 트리거하기에 적합한 장소 라고 생각 하므로 카운트 다운을 시작하는 데 사용할 것입니다. 초기화를 위해 어떤 다른 방법을 고려하고 있습니까?
dotnetom

특별히 염두에 두는 것은 없었지만 컴포넌트 내부에 너무 많은 "청크"를 사용하는 것은 어색해 보였습니다. React에서 비트와 조각이 어떻게 작동하는지에 익숙해지는 것은 나 자신이라고 생각합니다. 다시 한번 감사합니다!
Jose

4
렌더링에 영향을주지 않기 때문에 setInterval 값을 상태의 일부로 저장할 필요가 없습니다.
Gil

32

다음을 사용하여 10 초 카운트 다운 업데이트 class Clock extends Component

import React, { Component } from 'react';

class Clock extends Component {
  constructor(props){
    super(props);
    this.state = {currentCount: 10}
  }
  timer() {
    this.setState({
      currentCount: this.state.currentCount - 1
    })
    if(this.state.currentCount < 1) { 
      clearInterval(this.intervalId);
    }
  }
  componentDidMount() {
    this.intervalId = setInterval(this.timer.bind(this), 1000);
  }
  componentWillUnmount(){
    clearInterval(this.intervalId);
  }
  render() {
    return(
      <div>{this.state.currentCount}</div>
    );
  }
}

module.exports = Clock;

20

Hooks를 사용하여 10 초 카운트 다운이 업데이트되었습니다 (클래스를 작성하지 않고도 상태 및 기타 React 기능을 사용할 수있는 새로운 기능 제안. 현재 React v16.7.0-alpha에 있음).

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';

const Clock = () => {
    const [currentCount, setCount] = useState(10);
    const timer = () => setCount(currentCount - 1);

    useEffect(
        () => {
            if (currentCount <= 0) {
                return;
            }
            const id = setInterval(timer, 1000);
            return () => clearInterval(id);
        },
        [currentCount]
    );

    return <div>{currentCount}</div>;
};

const App = () => <Clock />;

ReactDOM.render(<App />, document.getElementById('root'));

React 16.8에서 React Hooks는 안정적인 릴리스로 제공됩니다.
Greg Herbowicz 2010

4

누구나 setInterval 구현에 대한 React Hook 접근 방식을 찾고 있다면. Dan Abramov는 그의 블로그에서 그것에 대해 이야기했습니다 . 클래스 접근 방식을 포함하여 주제에 대해 잘 읽으려면 확인하십시오. 기본적으로 코드는 setInterval을 선언적으로 바꾸는 사용자 정의 후크입니다.

function useInterval(callback, delay) {
  const savedCallback = useRef();

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}

편의를 위해 CodeSandbox 링크도 게시 : https://codesandbox.io/s/105x531vkq


2

감사합니다 @dotnetom, @ greg-herbowicz

"this.state is undefined"를 반환하는 경우-바인드 타이머 함수 :

constructor(props){
    super(props);
    this.state = {currentCount: 10}
    this.timer = this.timer.bind(this)
}

0

반응 클래스에서 매초마다 상태를 업데이트합니다. 내 index.js는 현재 시간을 반환하는 함수를 전달합니다.

import React from "react";

class App extends React.Component {
  constructor(props){
    super(props)

    this.state = {
      time: this.props.time,

    }        
  }
  updateMe() {
    setInterval(()=>{this.setState({time:this.state.time})},1000)        
  }
  render(){
  return (
    <div className="container">
      <h1>{this.state.time()}</h1>
      <button onClick={() => this.updateMe()}>Get Time</button>
    </div>
  );
}
}
export default App;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.