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.