hysryt / wiki

https://hysryt.github.io/wiki/
0 stars 0 forks source link

React #87

Open hysryt opened 6 years ago

hysryt commented 6 years ago

https://reactjs.org/

hysryt commented 6 years ago

重要な用語

hysryt commented 3 years ago

ステートフック(useState)

関数コンポーネントに state 機能を追加する。 ステートとはコンポーネントの状態(コンポーネントが持つデータ)のことを言う。 ステートは各コンポーネントごとに保持されるため、同じコンポーネントであっても値が共有されることはない。

useState 関数を呼び出すことでデータを表す変数とデータを更新する関数を得ることができる。

const [count, setCount] = useState(0);

count に現在のステートの値、setCount にステートの値を更新する関数が格納される。

注意点

useState は常に同じ順番で実行されなければならない。 つまり、if文の中に設置して特定の条件下でのみ実行する、ということはできない。 if文の中に設置しようとするとコンパイルエラーとなる。

hysryt commented 3 years ago

副作用フック(useEffect)

レンダー後に処理を追加する。

useEffect 関数を呼び出すことで処理を追加できる。

useEffect(() => {
  document.title = `You clicked ${count} times`;
});

useEffect で追加した処理は画面更新をブロックしない

画像更新ブロックさせる(画像更新と同期的に行う必要がある)場合は useLayoutEffect を使用する。

useEffect にわたした関数が戻り値として関数を返す場合、Reactはその関数をコンポーネントのアンマウント時と、2回目以降の副作用実行時の前に実行する。

第二引数には依存する変数を配列で指定できる。 依存する変数を指定することで、その変数が変更された時のみ処理を実行させることができる。

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]);  // count が変更された時のみ document.title を変更する
hysryt commented 3 years ago

ref

レンダーされたDOM要素あるいはReact要素への参照を取得する。

要素に対して関数を実行したい場合(canvas要素の描画など)などは props の受け渡しだけでは実現できない。 そのような場合はrefと要素のref属性を使ってその要素への参照を取得し、そのrefを使って関数を実行する。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.canvasRef = React.createRef();
  }

  componentDidUpdate(prevProps){
    const ctx = this.canvasRef.current.getContext("2d");
    // ...
  }

  render() {
    return <canvas ref={this.canvasRef} />;
  }
}

関数コンポーネントに対して ref 属性を使用することはできない。

hysryt commented 3 years ago

useRef

refと同じ働きをする。 それに加え、useRefは毎回のレンダーで同じオブジェクトを返すため、クラスのインスタンス変数のように使用することもできる。 監視されないステートとも言える。

hysryt commented 3 years ago

アプリケーションの作成

npx create-react-app my-app

TypeScriptを使用したい場合は、

npx create-react-app my-app --template typescript

webpackやbabelなどの設定が既に行われたアプリケーションを生成できる。

hysryt commented 3 years ago

memo

コンポーネントをメモ化する。

useMemo

関数をメモ化する。

hysryt commented 3 years ago

npm run build で生成されるファイル

コード分割

動的import

動的importしたコードはコード分割の対象となる。 React.lazyと一緒に使うことが多い。

React.lazy

コンポーネントの遅延読み込みを行う。

const AddButton = lazy(() => import('./AddButton'));

引数でPromiseを返す関数をとる。 そのPromiseはコンポーネントを解決する必要がある。 import は動的にコンポーネントを読み込む関数なのでそれに該当する。

React.lazy は関数を返す。 その関数はコンポーネントとして使用できる。 仕組み的には、その関数が実行されるとまずコンポーネントが既に読み込まれているかどうかを確認する。 読み込まれていればそれをそのまま返し、 読み込まれていなければReact.lazyに渡した関数を実行して読み込む。 このとき、そのPromiseをthrowする。 throwすることでSuspenseでキャッチでき、ローディング画面を表示できる。

React.lazy で import したコンポーネントは <Suspense> コンポーネントで囲う必要がある。

<Suspense fallback={<div>loading...</div>}>
  <AddButton disabled={item.trim() === ''} onClick={handleAdd} />
</Suspense>
hysryt commented 3 years ago

基礎

import ReactDOM from "react-dom";

ReactDOM.render(
  <div>Hello, World!</div>,
  document.getElementById('root');
);

この中の

<div>Hello, World!</div>

はJSXと呼ばれるシンタックスシュガー。 Babelによって、React要素を生成するJavaScriptへと変換される。

render 関数は第二引数の配下に第一引数のReact要素をDOM要素としてレンダリングする。

hysryt commented 3 years ago

コンポーネント

Reactアプリはコンポーネント単位で開発される。 コンポーネントは親子関係を持つことができる。

親コンポーネントから子コンポーネントへデータを受けわたす方法の一つとして、propsがある。 HTMLでいう属性。

<MyComponent name="john" />

上記の例では、MyComponentというコンポーネントに対して、propsでキーがname、値がjohnというデータを渡している。

子コンポーネント側では this.props.name で受け取った値(john)を取得できる。

hysryt commented 3 years ago

モジュール

Reactに限らずJavaScript全般で言えるが、モジュールは複数回importしたとしても実行されるのは一度のみ。 別々のファイルから同じモジュールをimportしたとしても実行されるのは一度のみ。 動的importの場合も同様。

hysryt commented 3 years ago

コンテキスト

親コンポーネントから受け渡すことなくデータを参照できる。 データを更新したい場合は更新用の関数を親コンポーネントから受け取る必要がある。

const MyContext = React.createContext(defaultValue);
<MyContext.Provider value={/* 何らかの値 */}>
  ...
</MyContext.Provider>
const theme = useContext(ThemeContext);

https://ja.reactjs.org/docs/context.html

hysryt commented 3 years ago

ルーティング

Reactを使ってサイトを作る場合は以下の方法がある。

Next.jsの方が機能が豊富に見える。

hysryt commented 3 years ago

ステート管理ライブラリ

ステートの管理を楽にする為のライブラリがいくつかある。

一般的には併用はせず、どれか一つを使う。

hysryt commented 3 years ago

useCallback

useCallback(fn, deps)

依存関係が同じ場合は常に同じコールバック関数を返す。

通常、コールバック関数は常に新規で生成される。

const callback = () => {
  console.log('callback!');
};

これをpropsとしてコンポーネントに渡すと、計算は同じでも別のコールバック関数と解釈される。 その結果、無駄な再レンダリングが発生する。

そこで、useCallback フックは依存関係が同じであれば同じコールバック関数を返す、という機能を提供する。 これを props に渡せば計算が同じであれば同じコールバック関数として解釈されるため、無駄な再レンダリングがなくなる。

const callback = useCallback(() => {
  console.log('callback');
}, []);

上記の場合は依存関係を何も指定していないため、常に同じコールバック関数を返す。

参考 https://qiita.com/uehaj/items/99f7cd014e2c0fa1fc4e https://blog.uhy.ooo/entry/2021-02-23/usecallback-custom-hooks/

hysryt commented 2 years ago

useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init);

Reduxでお馴染みのreducer。 引数のreducerにはアクションとステートをもとに新しいステートを返す関数を渡す。

reducerとstateが1対1になるという認識で良さそう。