react memo
React JSX内のループどうすんの?
code:jsx
<tbody>
for (var i=0; i < numrows; i++) {
<ObjectRow/>
}
</tbody>
これをやるとエラーになるよ!
こうするといい。
code:js
var rows = [];
for (var i = 0; i < numrows; i++) {
rows.push(ObjectRow());
}
return tbody(rows);
なおいいのが
code:js
var rows = [];
for (var i = 0; i < numrows; i++) {
// note: we add a key prop here to allow react to uniquely identify each
rows.push(<ObjectRow key={i} />);
}
return <tbody>{rows}</tbody>;
mapを使ってもいけるよ。
code:js
<tbody>
{objects.map(function(object, i){
return <ObjectRow obj={object} key={i} />;
})}
</tbody>
ES6:
code:js
<tbody>
{objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
stateとpropsの違い
stateとpropsはレンダー更新を切り替える。
props(propertiesの省略形)はコンポーネントの設定。上から受け取られ、それは不変。
propsは変更できるのに、不変にするべき?
propsを使うべき時、stateを使うべき時はどこ?
もしReactコンポーネントが必要であるデータを持つなら、propsをとおして渡され、getInitialState経由でReactコンポーネントを準備するべきか?
propsとstateは関係する。1つのコンポーネントのstateは子コンポーネントのpropsによくなる。propsはReact.createElement()の二番目の引数もしくは、もしJSXを使っているなら、より知っているタグ属性として親のレンダーメソッド内で子に渡される。
code:js
<MyChild name={this.state.childsName} />
子の名前の親のstate値は子のprops名になる。子の見通しから、命名propは不変。もし変更が必要なら、親は内部のstateを変更するべき。
code:js
this.setState({ childsName: 'New name' });
そして、Reactは子に伝わる。自然な後続の質問は子が命名propを変更する必要がある場合なのか?
これは子のイベントと親のコールバックを通してふつうは行う。子はイベント呼び出しを出す。例えば、onNameChanged。親はコールバックハンドラを渡すことでイベントを承諾する。
code:js
<MyChild name={this.state.childsName} onNameChanged={this.handleName} />
子は呼び出しによるイベントコールバックの引数として要求された新しい名前を渡す。this.props.onNameChanged('New name')と親はstateを更新するのにイベントハンドラでの名前を使う。
code:js
handleName: function(newName) {
this.setState({ childsName: newName });
}
1、なぜpropsは変更すべきでない?
これはReactの関数的な側面。すべてのデータは下向きに流れる。propは親によって所持されているので、親は親を変更すべき。理想的なのは、子がステートレスになるべき。現実には無理だけど...(Reactサイト上のformsドキュメントを参考)
2、データの紐づけを入れるのはどこか?getInitialStateのようなコンポーネントの初期化もしくはコンポーネントの外で入れたり、データが利用できる時にコンポーネントをレンダーするのか?
上部でどちらも与えることができる。これが推奨する方法で、もしくは分割オブジェクトで保存できる。1つの有名なアプローチはFlux。Storeを呼んだシングルトンオブジェクトを使う。これは大きなアーキテクチャパターンの一部。Facebookからのオープンソース化され、Reactを動かすために設計された。
onClickでメソッドに値を渡す方法
書くほどでもなかったのでの参考。割と初めてReact使ったことある人はつまずくところ。bind使う方法が一番古い方法だったのん。これからはアロー関数で書こうかな。
better wayが一番の方法みたいな流れになってる
Reactでスイッチング
例えばhide or showとか
基本中のキホンくらいかな。
このリンク見ればわかる
条件付き属性
属性名={真偽値など}で処理すればOK
少し主旨が違うけど
Reactで制御されていないインプットを変更することは?という質問に対して、間違ってはいないけど違うそうじゃない感。
この中に出てきたsingle source of trut
再描画を強制的にする方法
まず初めにこれをするためにstateに別に何も設定する必要はない。this.forceUpdate()を使うといいよが多数。試したらマジで更新された...
this.forceUpdate()はデフォルトで、コンポーネントのstateもしくはpropsを変更する時に、コンポーネントを再描画する。もしrender()メソッドがいくつかの他のデータに依存するなら、コンポーネントがforceUpdate()を呼ぶことで再描画が必要になるReactを呼ぶことができる。
shouldComponentUpdate()をスキップするために、this.forceUpdate()を呼ぶことはコンポーネント上で呼ばれるべきrender()を起こす。様々な子のshouldComponentUpdate()メソッドを含めるために、これは子コンポーネントの通常ライフサイクルメソッドをトリガーする。もしマークアップが変更するなら、ReactはDOMを更新する。
通常は、forceUpdate()のすべての使用を避けようとして、render()でのthis.propsとthis.stateから読もうとする。
ドキュメントに再描画ってある...
this.forceUpdate()のリファレンス:
this.setStateを呼び出すことは新しいrenderを呼び出す。
レンダー後のコードはどこに書けばよいか
componentDidMount()の中に書く。コンポーネントがレンダーされたあとに呼び出される。もしくは値が変更されるならcomponentDidUpdate()を使う。
ブラウザリサイズで再描画はどうするのか
この質問者はjQueryでのresizeをReactでどう表現するのかを聞いていた。
code:js
$( window ).resize(function() {
// re-render the component
});
これをどう表現するか。
Reactで親のstateをどうやって更新するのか
子コンポーネントにsetStateを渡す。ただ、この方法はメンテナンス面であまり良くなく、カプセル化を壊す。
もっと良い解決策として、
code:js
class Parent extends React.Component {
constructor(props) {
super(props)
this.handler = this.handler.bind(this)
}
handler() {
this.setState({
someVar: 'some value'
})
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <Button onClick = {this.props.handler}/ >
}
}
のように子コンポーネントに親コンポーネントにある関数を使って、stateを更新させる。子コンポーネントにstate更新の関数を渡し、それを子コンポーネントのpropsを使用して、親コンポーネントにある関数でstateを更新させる。
この質問では
code:js
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
の構造のコンポーネントがあることを想定して、5のコンポーネントから3のコンポーネントのstateを更新することの質問だが、この場合は、5と3は構造的には関係していないので、1と3を包んだ親コンポーネントを作る方が良い。
この質問のコメントにbindをなぜ使うのかという説明も書いてある。preventDefaultについても書いてくれてる。
ReactとReactDOMの違い
この二つはバージョン0.14で分かれた。ReactDOMはReactとDOMをくっつけるもの。ReactとReactDOMが別れた理由はReact Nativeを完成させるため。
ReactDOMはReactDOM.render、ReactDOM.unmountComponentAtNode,。ReactDOM.findDOMNodeを含む。サーバーサイド側でレンダリングをサポートしており、ReactDOMServer.renderToStringとReactDOMServer.renderToStaticMarkupで使えるらしい。
TypeError: this.setState is not a functionが出る
code:js
var AppMain = React.createClass({
getInitialState: function() {
return{
FirstName: " "
};
},
componentDidMount:function(){
VK.init(function(){
console.info("API initialisation successful");
VK.api('users.get',{fields: 'photo_50'},function(data){
if(data.response){
this.setState({ //the error happens here
FirstName: data.response0.first_name });
console.info(this.state.FirstName);
}
});
}, function(){
console.info("API initialisation failed");
}, '5.34');
},
render:function(){
return (
<div className="appMain">
<Header />
</div>
);
}
});
このコードを実装するとTypeError: this.setState is not a functionというエラーメッセージが出る。
これの解決策として、アロー関数を使う。
code:js
VK.api('users.get',{fields: 'photo_50'},(data) => {
if(data.response){
this.setState({ //the error happens here
FirstName: data.response0.first_name });
console.info(this.state.FirstName);
}
});
Reactでscriptタグをどうやって加えるのか?
code:js
'use strict';
import '../../styles/pages/people.scss';
import React, { Component } from 'react';
import DocumentTitle from 'react-document-title';
import { prefix } from '../../core/util';
export default class extends Component {
render() {
return (
<DocumentTitle title="People">
<h1 className="tk-brandon-grotesque">People</h1>
<script dangerouslySetInnerHTML={{__html: 'try{Typekit.load({ async: true });}catch(e){}'}}></script>
</article>
</DocumentTitle>
);
}
};
で行うと問題が起こる。
少し古い方法
code:js
componentDidMount () {
const script = document.createElement("script");
script.async = true;
document.body.appendChild(script);
}
hooksを使う
code:js
useEffect(() => {
const script = document.createElement('script');
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
}
}, []);
Helmetを使う方法もある
code:js
import React from "react";
import {Helmet} from "react-helmet";
class Application extends React.Component {
render () {
return (
<div className="application">
<Helmet>
<script>try{Typekit.load({ async: true });}catch(e){}</script>
</Helmet>
...
</div>
);
}
};
変数でHTMLを追加する
dangerouslySetInnerHTMLを使うといいらしい。ただこれを使うとインジェクションの危険がある。
クラスコンポーネントと関数コンポーネントの違い
関数コンポーネントはライフサイクルメソッドや内部にstateを持っていなければ使用するべき。ただし、hooksの出現によってはわからない。
hooksでの説明
componentDidUpdateはuseEffect(fn)を代わりにできる。fnはレンダリングを起動するための関数。
componentDidMountメソッドはuseEffect(fn, [])の代わりにできる。fnはレンダリングを起動するための関数で、[]はコンポーネントがレンダーするオブジェクトの配列で、1つがレンダーする前に値を変更した場合に必要。useEffect()はいったん起動し、初めにマウントする。
stateはuseState()の代わりにすることができる。stateの参照とstate(すなわち、const [state, setState] = useState(initState))を準備できる関数を破壊させることができる。
Facebookでは関数コンポーネントを推奨している。ただ、関数コンポーネントはパフォーマンスが悪いといわれていて、それはイベントハンドラ関数が関数コンポーネントでレンダーリングごとに再定義されているから。実際にこれはuseCallbackやuseMemoを使うと再定義を防ぐことができる。
参照:
気になるリンク
Can I use lifecycle method on React Hooks?
Hooks can use controlling state and props in function. Lifecycle method in React cannot use in function but can work lifecycle method in function using React Hooks?
↓ここに答えあった
propsからstateの初期化
これはアンチパターン
ReactのUncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.がでたとき
js:
code:js
/** @jsx React.DOM */
'use strict';
var React = require('react');
var App = React.createClass({
render() {
return <h1>Yo</h1>;
}
});
React.renderComponent(<App />, document.body);
HTML:
code:html
<html>
<head>
<script src="/bundle.js"></script>
</head>
<body>
</body>
</html>
headでscriptタグを書いているので、document要素がまだ利用できない状態。なのでbodyタグの一番最後に書くこと。
なぜVirtual DOMのReactの概念はdirty model checkingよりパフォーマンスが高いのか?
まず、ここに出てくるdirty-checkingを知らない。
dirty checking 参考:
dirty checkingはパフォーマンスが遅くなる。でも、virtual DOMとの比較されていない。
virtual DOMモジュール開発者の人によると、Reactのstateはobservableと同じような性質を持っており、dirty checkingは定期的な間隔でデータを入れなければならず、再帰的なデータ構造ですべての値を確認する必要があるのでobservableより遅い。
virtual DOMはDOMの効率的な再描画として使われる。これはデータのdirty checkingと関係なくdirty checkingあるなしにかかわらずvirtual DOMを使って再描画できる。
setPropsっていうのがあるらしい。setStateを使うときに再描画する。
Reactイベントオブジェクトからカスタム属性にどうやってアクセスするのか
カスタム属性
code:html
<div data-custom-attribute="foo" />
要素とdata-プロパティはHTMLをレンダーする。styleのような標準プロパティはevent.target.styleとしてアクセスさせることができる。
event.targetはネイティブDOMノードを与え、その時に属性をアクセスするため標準のDOM APIを使う必要がある。event.target.dataset.tagもしくはevent.target.getAttribute('data-tag')のどちらでもすることができる。
あとは
var attribute = event.target.attributes.getNamedItem('data-tag').value;
でもできる。
Reactはlabel要素のfor属性を無視する
for属性はDOMプロパティAPIで一貫性によりhtmlForと呼ばれる。もしReactの開発ビルドを使っているなら、コンソールで警告を見るべき。
ReactでDOM要素にどうやってアクセスするか?Reactでdocument.getElementById()に等しいのは何か?
refでDOMにアクセスできる。
super()とsuper(props)の違い
propsにアクセスするためにはconstructorでpropsを渡す必要がある。super(props)を書かなければそのコンポーネント上でpropsが使用できない。
Virtual DOM
virtual DOMは実際のDOMを更新する代わりに更新する。
新しい要素がUIに加えられたとき、作られたツリーとして表現される。様々な要素はツリー上のノードである。もしこれらの要素のstateが変更するなら、新しいvirtual DOMツリーが作られる。このツリーは前のvirtual DOMツリーによって比べられ”diffされる”。
virtual DOMは実際のDOMの変更を作るために一番可能なメソッドを計算する。これは実際のDOM上で最小限の操作があることを保証する。したがって、実際のDOMを更新するパフォーマンスコストを削減する。
https://i1.wp.com/programmingwithmosh.com/wp-content/uploads/2018/11/lnrn_0201.png?ssl=1
赤い丸は変更したノードを表している。これらのノードはstateが変更したUI要素を表現する。virtual DOMツリーの前のバージョンと現在のvirtual DOMツリーとの間の違いはその時に計算される。全体のサブツリーは更新されたUIを与えるために再描画される。この更新されたツリーは実際のDOMをバッチ更新させる。
ReactでUIピースはコンポーネントであり、様々なコンポーネントはstateを持つ。Reactはobservableパターンを導いて、state変化を通知する。コンポーネントのstateが変更したとき、Reactはvirtual DOMツリーを更新する。virtual DOMは更新され、Reactはvirtual DOMの前のバージョンによってvirtual DOMの現在のバージョンと比較する。このプロセスは"diffing"と呼ばれる。
virtual DOMの操作は画面には何も描画しないのではやい。
DOM Objectの記事:
React lifecycle
コンポーネントにはライフサイクルがあり、主に3つのフェーズがある:Mounting、Updating、Unmounting。
Mounting
DOMに要素を入れるときのフェーズ。
Reactはbuilt-inメソッドを持つ。mountingされたときに以下の順で呼び出される。
1. constructor()
2. getDerivedStateFromProps()
3. render()
4. componentDidMount()
render()メソッドは要求され、いつも呼ばれる。その他はオプションで、もし定義したなら呼ばれる。
updating
コンポーネントが更新されたときが次のフェーズ。
コンポーネントはコンポーネントのstateもしくはpropsでの変更があるときに更新される。
Reactは5つのbuild-inメソッドがある。コンポーネントが更新されたときに呼び出される。
1. getDerivedStateFromProps()
2. shouldComponentUpdate()
3. render()
4. getSnapshotBeforeUpdate()
5. componentDidUpdate()
render()メソッドは要求され、いつも呼ばれる。その他はオプションで、もし定義したなら呼ばれる。
Unmounting
コンポーネントがDOMから削除されたときに呼び出されるライフサイクル。
Reactはコンポーネントがunmountされたときにbuild-inメソッドを1つ呼び出す。
1. componentWillUnmount()
constructor
stateを初期化するときやpropsを引数にする(superを入れること)とpropertyを使える。
stateとbindメソッドを使わないなら実装しなくていい。
マウントされる前に呼ばれる。
ここにはsetStateメソッドを使うのはだめ。stateの初期化は
code:js
this.state = { counter: 0 };
にすること。
このメソッド以外でstateを使う場合は、setStateメソッドを使うこと。
side-effectsやsubscriptionsを使う場合はcomponentDidMountメソッドを使うこと。
constructorではstateにpropsをコピーとして使うのは良くない。this.propsであればよし。
propsをstateの初期値で設定するとstateが更新されなくなる。
getDerivedStateFromProps
componentDidUpdateの代わりにgetDerivedStateFromPropsが使われる。componentDidUpdate + setState = getDerivedStateFromPropsらしい。
getDerivedStateFromPropsは新しいprops、setState、forceUpdateが呼ばれたときに呼ばれる。
16.4ではsetStateが呼ばれた時にgetDerivedStateFromPropsが呼ばれる。
stateを更新するためのオブジェクトを返すべき。
stateがpropsの変更に依存するレアユースケースで存在する。
以下条件の時は他のメソッドを使うこと:
propsの変更に応じて副作用(たとえば、データの取得やアニメーション)を実行する必要がある場合は、代わりにcomponentDidUpdateライフサイクルを使用すること。
もしprops変更時にstateをリセットしたい場合、keyを完全な管理するか完全に管理していないコンポーネントを作ることを考えること。
render
クラスコンポーネントで必要になるメソッド。
renderメソッドは以下の型を返す:
React要素。
配列とフラグメント
ポータル
文字列と数
真偽値とnull
この関数は常に純粋であるべきで、同じ結果を返すこと。ブラウザに作用させる必要がある場合はcomponentDidMount()か他のライフサイクルメソッドを使うこと。
componentDidMount
コンポーネントがマウントした後にすぐに呼び出されるメソッド。DOMを要求する初期化はここで行うこと。
外部からのデータをロードするときにこのメソッドを使用するのは良いこと。
componentDidMount()でsetState()をすぐに呼び出すことができる。ブラウザが画面を更新する前にレンダリングをトリガーする。これはrender()が2かい呼び出されることになり、これがパフォーマンス問題になる。stateの初期化はconstructor()でできるようにするべき。
shouldComponentUpdate
コンポーネントの出力がstateもしくはpropsの現在の変更で影響を受けないか知らせる。
このメソッドは新しいpropsもしくは新しいstateが投げられたときにレンダリングする前に呼び出される。デフォルトはtrue。初期レンダーもしくはforceUpdate()を使うときには呼ばれない。
このメソッドを使う代わりにPureComponentを使う。PureComponentはstateとpropsのshallow comparisonを行う。
shouldComponentUpdateがfalseならUNSAFE_componentWillUpdate()、render()、componentDidUpdate()は呼び出されない。
getSnapshotBeforeUpdate
getSnapshotBeforeUpdateは最新のレンダーされた出力がDOMを出す前に呼び出される。このライフサイクルメソッドで返される値はcomponentDidUpdateの引数に渡される。
componentDidUpdate
更新後にすぐに呼び出されるメソッド。初めのレンダーでは呼ばれない。
このメソッドは現在のpropsと前のpropsを比較して、ネットワークリクエストを行うのに最適な場所。
もしコンポーネントでgetSnapshotBeforeUpdateを使う場合、componentDidUpdateの第三引数のsnapshotが渡される。
componentWillUnmount
props.children
Reactは'generic boxes'を表現し、事前に子を知らないコンポーネント上のprops.childrenを使うことができる。
props.childrenはコンポーネントを呼び出す時に開始タグと終了タグの間を含めることで使われる。
React Hooks