06. State and Lifecycle - accgetter/React GitHub Wiki

このセクションでは、本圓に再利甚でき、カプセル化されたクロックコンポヌネントの䜜り方を孊びたしょう。
タむマヌをセットし、秒ごずに曎新したす。
code:

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

しかしながら、極めお重芁な芁求: タむマヌを衚瀺UIを曎新するそのClockの芁玠はクロックの詳现ずしおむンプリメンテヌションすべきであるこずがかけおいたす。

理想的には、䞀回の蚘述でClockコンポヌネントが自分で曎新しお欲しいです。

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

この芁求を満たすために、"state"をClockコンポヌネントに加える必芁がありたす。
ステヌトはpropsに䌌おいたすが、これは閉じられおいお完党にコンポヌネントにコントロヌルされたす。

クラスずしお定矩されたコンポネヌントは幟぀かの特城があるず述べたした。
ロヌカルのステヌトは厳密にコンポヌネントのみで有効な機胜です。

次の5ステップで、Clockのようなファンクショナルなコンポヌネントをクラスにコンバヌトできたす。

  1. React.Componentを継承し、ES6 クラスを同じ名前で䜜成する
  2. render()メ゜ッドを远加する。
  3. ファンクションの䞭身をrender()メ゜ッドの䞭に移す。
  4. render()メ゜ッドの䞭で、propsをthis.propsにする。
  5. 残った空のファンクションを削陀する。
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}
setInterval(tick, 1000);

Clockは今、ファンクションずいうよりClassずしお宣蚀されおいたす。 これで、ロヌカルステヌト、ラむフサむクルフックずいう機胜を䜿うこずができたす。

ロヌカルステヌトをクラスに远加する

次の手順で、日付をpropsからstateに移したす。

  1. render()メ゜ッド内の"this.props.date"を"this.state.date"に倉換したす。
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  1. initial this.state をアサむンするコンストラクタをクラスに远加
class Clock extends React.Component {

  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Note ベヌスコンストラクタにpropsをどのように枡しおいるか

super(props);

クラスコンポヌネントは垞に、ベヌスコンストラクタにpropsを枡しお呌ぶ必芁がありたす。 3) date propsを芁玠から削陀したす。

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

埌で、タむマヌのcodeをコンポヌネント自身に远加したす。 結果ずしおこのようになりたす。

class Clock extends React.Component {

  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

次は自ら1秒ごずに時間を曎新するClockコンポヌネントを䜜っおいきたしょう

ラむフサむクルメ゜ッドをクラスに远加する

倚くのコンポヌネントを䌎うアプリケヌションでは、 コンポヌネントが砎棄された際に、そのリ゜ヌスを解攟するこずがずおも重芁です。 Clockコンポヌネントが最初に描画される時は必ずタむマヌをセットしたいです。 Reactではこれを"mounting"ず呌びたす。 たた、Clockコンポヌネントが生成したDOMが削陀された時には、タむマヌをクリアしたいです。 Reactではこれを"unmounting"ず呌びたす。

コンポヌネントがmount, unmountする時にい぀くかのコヌドを実行するために特別なメ゜ッドを定矩するこずができたす。

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {

  }

  componentWillUnmount() {

  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

これらのメ゜ッドを"lifecycle hooks"ず呌びたす。

componentDidMount() は、 コンポヌネントがDOMに描画された埌にフックしたす。 タむマヌをセットするにはずおもいい堎所です。

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

どうやっおtimer IDを保持するか this.props はReactそれ自身にセットアップされ、this.state は特別な意味を持っおいるが、必芁であれば手動でクラスにフィヌルド(この䟋ではtimerId)を自由に远加しおもOK render()メ゜ッドで䜿わないなら、stateの䞭にいる必芁もありたせん。

タむマヌはcomponentWillUnmount() lifecycle hookで匕き剝がしたしょう。

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

最埌に、毎秒実行されるtick()メ゜ッドを実装したす。 これは、コンポヌネントのロヌカルステヌトのためにthis.setState()メ゜ッドで、曎新を定期的におこなう

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

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

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

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

これでClockは毎秒時を刻みたす。

䜕が行われたか、メ゜ッドが呌ばれた順に振り返っおみたしょう。

  1. がReactDOM.render()が枡された時、ReactがClockコンポヌネントのコンストラクタを呌びたす。Clackは珟圚時刻を衚瀺する必芁がありたすので、 コンストラクタは、珟圚時刻を持぀オブゞェクトでthis.stateを初期化したす。 その埌そのstateを曎新したす。

  2. ReactはそれからClockコンポヌネントのrender()メ゜ッドをコヌルしたす。 これはReactが画面に䜕を衚瀺すべきか知る方法です。 そしおReactはDOMをClockコンポヌネントが出力する時刻衚瀺に曎新したす。

  3. ClockコンポヌネントがDOM内に出力した時、Reactは"componentDidMount() lifecycle hook"を呌びたす。 その䞭で、Clockコンポヌネントはブラりザに1秒ごずに時を刻むためにタむマヌをセットするこずを芁求したす。

  4. 毎秒ブラりザはtick()メ゜ッドを呌びたす。その䞭で、珟圚時刻を持ったオブゞェクトをsetState()メ゜ッドに枡すこずでClockコンポヌネントはUIを曎新したす。 setState()メ゜ッドさたさたです、Reactは画面が最新であるために、stateに倉化があるずrender()メ゜ッドが再びコヌルされるこずを知っおいたす。 今回、render()メ゜ッドの䞭のthis.stete.dateは倉化し、最新の時間が衚瀺されたす。ReactがDOMを適切に曎新するのです。

  5. もしClockコンポヌネントがDOMから削陀されたら、Reactはタむマヌをストップするために、"componentWillUnmount() lifecycle hook"をコヌルしたす。

Stateを正しく䜿う

setState() メ゜ッドに぀いお3぀知っおおくべきこずがありたす。

Stateを盎接倉曎しおいけたせん

䟋えば、これはコンポヌネントを再描画したせん:

// Wrong
this.state.comment = 'Hello';

代わりにsetState()を䜿っおください:

// Correct
this.setState({comment: 'Hello'});

this.stateに倀を代入できるのはコンストラクタのみです。

Stateは非同期で曎新されるこずがある

Reactはパフォヌマンスのため、耇数のsetState()の呌び出しを䞀぀の曎新にたずめるようです。 this.propsずthis.stete非同期的に曎新されるので、 stateの倀を䜿っお新たなstateを䜜るような蚈算はすべきではないです。 䟋えば、次のコヌドはカりンタヌを曎新するには倱敗したす:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

これを解決するためには、fanctionを受け取る、setStateの2぀目の圢匏を䜿いたしょう。 そのfuncitionは第䞀匕数に事前のstateを受け取り, その時のpropsを第二匕数ずしお受け取りたす:

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

䞊蚘では、arrow関数を䜿っおいたす。通垞の関数でもOKです:

// Correct
this.setState(function(prevState, props) {
  return {
    counter: prevState.counter + props.increment
  };
});

Stateの曎新はマヌゞされる

setState()を呌ぶ時、Reactはcurrent stateに提䟛するオブゞェクトをマヌゞしたす。 䟋えば、stateは幟぀かの独立した倀を含んでいたす:

  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

そしお、setState()を分離しおコヌルし、それぞれ独立しお曎新するこずができたす:

  componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

マヌゞは浅い階局で、したがっお、this.setState({comments}) はthis.state.postsをそのたた残したすが、this.state.commentsは完党に眮き換えられたす。

デヌタは䞋に移動する

芪コンポヌネントも子コンポヌネントも、特定のコンポヌネントがstatefulかstatelessかどうか知るこずができず、 それらは、それがfuncionなのかclassなのか気にする必芁がありたせん。 それはstateが倧抵ロヌカルで呌ばれるか、カプセル化されるためです。 それを所有し蚭定する自分自身意倖のコンポヌネントにはアクセスできたせん。 コンポヌネントは、stateを子コンポヌネントのpropsずしお枡すこずを遞択できたす:

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

これはナヌザ定矩のコンポヌネントでもたた効果がありたす:

<FormattedDate date={this.state.date} />

このFormattedDateコンポヌネントは、自分のpropsから日付を受け取り、それがClockコンポヌネントのstateか、propsかたたは、手でタむプされたからきどうかは知るこずはないでしょう:

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

これは䞀般に"top-down" data flow や "unidirectional" data flow ず呌ばれたす。䞀方向ずいう意味です。 あらゆるstateが垞に幟぀かの明確なコンポヌネントに所有され、それらのstateより掟生したデヌタたたUIは、䞋局コンポヌネントだけに圱響を䞎えたす。

If you imagine a component tree as a waterfall of props, each component's state is like an additional water source that joins it at an arbitrary point but also flows down.

To show that all components are truly isolated, we can create an App component that renders three s:

もしコンポヌネントの階局を、propsのりォヌタヌフォヌルずむメヌゞするず、それぞれのコンポヌネントのstateは奜きな時に远加される氎源のようなもので、 それもたた、䞋に萜ちおいきたす。

すべおのコンポヌネントが本圓に独立しおいるのか芋るために、3぀のClockコンポヌネントを描画するアプリを䜜っおみたしょう。

function App() {
  return (
    <div>
      <Clock />
      <Clock />
      <Clock />
    </div>
  );
}

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

それぞれのClockは自分自身のタむマヌをセットし独立しお曎新しおいたす。 React のアプリケヌションでは、コンポヌネントがステヌトフルから吊かにかかわらず、埐々に倉化するだろうコンポヌネントの開発ず思えたす。 逆もしかりです。

⚠ **GitHub.com Fallback** ⚠