【Reactのstateとpropsの違いが知りたい!(変更・更新の仕方等デモあり)】過去のReact初心者の自分にpropsとstateの違いを説明する

水色
この記事は2016年に投稿した記事で、今では古い書き方になっているかもしれませんが、考え方は一緒です。(2020/4/30)
ややわかり始めたReact、1年前にこういう記事かいて、今結構検索でヒットするみたいなので
、過去の自分にちょっと説明したらこんな感じかなと思って書きます。
ここの記事ではこのコードをできるだけ簡単に説明しています。説明と照らし合わせて確認していただけたら幸いです。(PCでご覧になると表示がわかりやすいです)
propsとstateの簡単な説明
下記コードをみてください。
<ParentComponent />
こういうコンポーネントがあって、
ParentComponentはこういうDOMを返すとします。
<div>
<h1>親です</h1>
<ChildComponent />
</div>
「返す」というのは、Reactではコンポーネント単位でrenderメソッドというものを必ず実装しなくてはならず、そのメソッドはDOMを返さなくてはなりません。
まだちょっとよく馴染みがない方は、
この
この
なので今回は上記のように返すとします。
この親がrenderメソッドで返すChildComponentコンポーネントは
<div>
<h2>題名</h2>
わたしの未来
</div>
というDOMを返すようにします。
なので最終的なの描画は
<!--ここからParentComponentが返すDOM -->
<div>
<h1>親です</h1>
<!--ここChildComponentが返すDOM -->
<div>
<h2>題名</h2>
わたしの未来
<!--ここまでChildComponentが返すDOM -->
</div>
</div>
<!--ここまでParentComponentが返すDOM -->
こうなります(実際のというのはやや語弊がありますが、説明のため端的にいっています。)
この「わたし」のところを可変にしたいとします。(状態を管理するといいます)
その場合親のrenderメソッド内でpropsとして渡す(今回は親がstateとして管理する場合を説明)
<div>
<h1>親です</h1>
<ChildComponent name={this.state.name}/>
</div>
</div>
こう。(親から子供に値をわたすイメージです。)
で子供側では
<div>
<h2>題名</h2>
{this.props.name}の未来
</div>
このように参照する。(親から値を受け取るイメージです。)
これが何をしているのか最初のうちはわからなかった。
これは「name属性として子供のコンポーネントに親で管理しているthis.state.name
値を渡しています。」
name属性というのは任意の名前でつけます。
なんでもいいです。
この
name={this.state.name}
のname
が属性
this.state.name
が状態です
name
属性は子供から参照する際の
this.props.name
の
name
部分にあたります。
例えばこれが
menber={this.state.name}
とされていたら
子供では
this.props.menber
としてthis.state.name
値を受け取れるということです。
で、今回の場合
this.state.name
に初期値として「わたし」を設定します。(後述///code1をみてください。このようにします)
なぜ「親から値を渡して子供は受け取る」とかそんなことしているか??
親で値を管理すると
その値が変わると子供にその変更が伝わり、
その子供の子供に変更が伝わりと再レンダリングされます。
少し乱暴に言うと親のstate
値が変わった子供のDOMしか再描画されないので、パフォーマンスよく描画できます。
またcomponent
が状態を管理し、値は親から子供への一方通行で渡されるので分かりやすいんですね。
さらに可搬性が良くなります。部品部品で取り扱いやすくなります。
this.state.name
。
これを「値を管理している」といいます。
可変にしたいプロパティを指定します
一方this.props.name
。これは不変な値です。参照のみでここに値を直接変更してはいけません。
this.props.name = "morita";
これは代入しちゃっています。
props
は親から値を受け取るか、初期値として設定するかですので、これをrenderメソッド内でしてはいけません。
propsはread only。読み取り専用です。こうしたい場合はstateに変更します。
ついでにいうと
this.state.name = "morita";
これもアンチパターンです。
stateの更新はsetStateでします。
setState({name : name + "さん"});
こういうのはありです。
あとsetStateをrenderメソッド内で呼んではいけません
話を戻して、、
this.state.name
は状態が変わる値です。
例えば、下は子供Componentが
render(){
return(
<div>
<h2>題名</h2>
{this.props.name}の未来
</div>
)
}
renderメソッド内で親が渡している値this.props.[親の属性値]
(親でいうthis.state.name)の状態を参照しています
当然親のthis.state.name
値が変わると参照している子供の値も変わるので状態が変わる度にレンダリングされます。
(ライフサイクルメソッド内のcomponentwillreceiveprops
で描画をコントロールできますが。。それはまた)
これで親の状態が変わったらnameも変わる簡単なコンポーネントのできあがりですね。
親の方では
//code1
this.state = {
name: 'わたし'
}
をdefaultとしたり
defaultはpropsとして自分自身の値を参照すればこのような書き方になりますよ
this.stata = {
name : this.props.name
}
ChildComponent.defaultProps = {
name : 'わたし'
}
babelをstage-0とすれば
static name = 'わたし'
こういう風にかけたり、
もしくは
親の
<ParentComponent name={'わたし'}>
とすれば初期設定できます
このようにして、UserActionがあったら
そのメソッド内で下の用に呼び出します。
例えばこうです
onClick = ()=>{
const name = 'あなた';
this.setState({
name: name
});
}
このstateを管理している親のメンバメソッドでsetStateを呼び出すことでそれ以下のコンポーネントは再レンダリングされるので
このインスタンス
<ChildComponent name={this.state.name}/>
これが子供でよみこまれる時には
name={"あなた"}
が渡っています。
子供のrender時のここが変わる
<div>
<h2>題名</h2>
あなたの未来
</div>
こうなります。
これの何が嬉しいかは
これが下のようにリストとして表示したい場合、同じDOMを書くのはだるいので
コンポーネントを複数書く。
でもその中でレンダリングするDOMは固有のものにしたい。なんて時は
//ParentComponent内のrenderメソッド内で
<div>
<h1>親です</h1>
<ChildComponent num={1} name={this.state.name} />
</div>
<div>
<h1>親です</h1>
<ChildComponent num={2} name={this.state.name} />
</div>
子供にpropsとしてnum
を渡すことでChildComponent
内のrenderメソッド内でprops.this.num
が1の時で挙動を変えれたりするんですね。
例 親から渡ってきたnum
が1だったらclassName
を変えたりする
//ChildComponent内で
render(){
const color = this.props.num === 1 ? 'red' : 'blue';
return (
<div className={color}>
子供のDOM
</div>
)
}
//例 親から渡ってきたnumが1だったらさらにComponentを返す
//ChildComponent内で
render(){
const DOM = this.props.num === 1 && <GroundChildComponent />;
return (
<div>{DOM}</div>
)
}
とか
子供の中で返すDOMやスタイルを変更したりする
ふう。
どうでしたでしょうか。。
Reactのpropsとstateがいまいち腑に落ちない方へ助けになれたら幸いです。
こちらに今回のdemoをはっ付けておきます(PCから見るとちゃんと描画されるみたい。。)
playground
https://github.com/kenmori/React-ES6-Flux-Playground/tree/master/playground
今回のコード全部
「武骨日記の」プライバシーポリシーに関して
・プライバシーポリシー
・個人情報取り扱いに関して
・サイトTOP
・私は何者か
・29歳よしもと芸人がWebデザイナー未経験で学校に通い5年後フリーランスのフロントエンドエンジニアになるためにやった9つのこと
・フロント記事
・フロントエンドエンジニア
・フロントエンド記事(タグ)
・TypeScript
・TypeScript練習問題集
・【TypeScript】TypeSript中級者になる為に知っておくと良い108個のこと
・JavaScript練習問題
・styled-componentsの使い方
・SCSS問題集
・GraphQL「Apollo x Relay-Style-Cursor-Pagination(リレースタイルカーソルページネーション)」
・recomposeと仲良くなりたい
・機動戦士FlowType
・初めてReactNativeWebを触ってみて
・Ramda.jsシグネチャの読み方
・環境変数の話
・いちごタルトの作り方
・フロントエンドエンジニア豚汁の作り方
「武骨日記の」プライバシーポリシーに関して
プライバシーポリシー
株式会社TerraceTechについて
最近起業しました。
・株式会社TerraceTech
SNS
・しずかなインターネット kenjimorita
・インド旅 instagram
・適当な日常写真 instagram
・シュールさーん instagram
・シュールさーん LINEスタンプ
・もりたけんじTwitter
・ネタ帳Twitter
・note
※わたしが結成しているWebチームではWeb未経験者、フリーランスの方へのお仕事を紹介しています。
また個人レッスンしてほしい生徒も募集中です。
もしご興味ある方はチャットからご連絡ください。
※業務連絡やお久しぶり連絡もチャットからお願いします。