React.js入門

はじめに
React.jsの入門編についてReact + TypeScriptをベースに解説いたします。
これを読んでもっと知りたいと思った方は是非公式チュートリアルをお試しください。
https://ja.reactjs.org/tutorial/tutorial.html
環境構築
Nodeとnpmのインストール確認
まずはパッケージ管理ツールであるnpmを利用するためにNodeをインストールします。
下のリンクからnodeのインストーラをダウンロードし、インストールを行ってください。
https://nodejs.org/ja/ ※バージョンは日々新しくなります。
$ node -v
v16.4.2
バージョンを確認します。
$ npm -v
7.18.1
Visual Studio Codeのインストール
次に、統合開発環境のVisual Studio Codeをインストールします。
Atomなどでも問題ないですが、個人的に一番便利なのがVisual Studio Codeだと思っています。
https://code.visualstudio.com/download
Visual Studio Codeの日本語化
必要に応じて日本語化が可能です。
- Visual Studio Codeを開き、サイドバーから拡張機能のストアに移動します。

- 検索欄に
Japanese
と打ち、Japanese Language Pack
をインストールします。 - Visual Studio Codeを再起動します。
Reactの導入
こんかいはcreate react appという、react公式が提供している環境の一括インストールを利用します。
Visual Studio Codeのターミナルで任意のディレクトリを開き下記のコマンドを実行してください。
$ npx create-react-app {任意のプロジェクト名} --template typescript
Need to install the following packages:
create-react-app
Ok to proceed? (y)
create-react-appをインストールしますか?と聞かれるのでYesと答えます。
確認
このようにいくつかのファイルが生成されていればインストール成功です。

それでは、実際に動かしてみましょう。
$ npm start
インストールが成功したディレクトリに移動し、上記のコードを入力してください。

ターミナルにこんな文字が表示されれば成功です。Local: http://localhost:3000
ターミナルの3行目に記載されたこのURLをブラウザで開いてみてください。

このような画面が表示されたと思います。
これで無事Reactの導入完了になります。
JSXとは
Reactでは、コンポーネントをJSXという記法で記述していきます。
実際のコードで書くと、次のようになります。
const App =() => {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
見た目はほぼHTMLなので、馴染みやすいかと思います。
実際にこのコードはHTMLに変換され、画面に描画されます。
そして別のファイルなどで以下のように書くことで、コンポーネントを呼び出すことができます。
<App />
このように、コンポーネントは最初を大文字にし、JSXをreturnするという決まりがあります。
つまり、JSXをreturnする関数=コンポーネントという理解でOKです。
JSXとは(発展編)
次に、少し発展したJSXの説明をしていきます。
まず、JSXとはcreateElementという画面を描画するための関数の実行を意味します。
そして、その結果はオブジェクトに変換されるので、オブジェクトのように扱うことができます。
例えば、次のように変数にJSXを入れたりすることもできます。
const obj = <div>test</div>
そして、JSXの中では{}で囲むことで、JavaScriptの式を書くことができます。
式と文の違いが分からないという人がいるかもですが、式は変数に代入できるもの、文はif文のように{}で囲む必要があるものという理解で十分です。
const test = "hoge"
return (
<div className="App">
{test === "hoge" ? "hello" : "good bye"}
</div>
);
}
ちなみに、この{}の中ではbooleanの値、nullとundefinedは表示されません。
また、配列は勝手に展開されて表示されます。
const arr = ["hoge","foo","bar"]
return (
<div className="App">
{arr /* hogefoobar */}
</div>
);
Propsとは
次に、Propsについて説明していきます。
Propsは簡単に言うと、コンポーネントに渡す引数になります。
例えば、次のように使います。
const App =(props) => {
return (
<div className="App">
{props.hoge}
</div>
);
}
<App hoge={"hoge"} />
このように、プロパティ名={値}としてpropsを渡すことができます。
そして、このpropsは親から子にのみ渡すことができます。
なので、子から親にpropsを渡すことはできません。
また、propsは変更ができないようになっているので、変更しようとするとエラーになります。
そして、propsは以下のようにchildreを使うことで、コンポーネントを渡すこともできます。
const Comp = (props) => {
return(
<>
<div>Hello</div>
{props.children /* <div>こんにちは</div> */}
</>
)
}
const App =(props) => {
return (
<div className="App">
<Comp>
<div>こんにちは</div>
</Comp>
</div>
);
}
React Fragment
先ほど、<> </>
というJSXが出てきましたが、何だか分からない人も多かったかと思います。
まず、Reactにおいてトップレベルの階層は、nodeが2つあってはならないという決まりがあります。
なので、次のように書くとエラーになります。
const Comp = (props) => {
return(
<div>Hello</div>
{props.children /* <div>こんにちは</div> */}
)
}
トップレベルをdivで囲めば解決なのですが、そうすると無駄な要素が増えてしまいます。
そんな時に<> </>
で囲むことで、無駄な要素を増やさずにエラーも防ぐことができます。
ちなみに、この記号は元々<React.Fragment> </React.Fragment>
と書いていましたが、省略して書けるようになりました。
Stateとは
Stateとは、コンポーネントの状態を意味します。
要は、コンポーネント毎に値を保管しておくことができます。
そもそもstateの必要性がイマイチ分からないと思うので、そこから説明していきます。
例えば、以下のようなコンポーネントを定義したとします。
const Counter = () => {
let num = 0
const onClickButton = () => {
num +=1
console.log(num)
}
return (
<>
{num}
<button onClick={onClickButton}>+1</button>
</>
)
}
ボタンを押すごとに、1ずつプラスされた値が表示される想定です。
ところが、ボタンを押しても表示される値は0のままになります。
理由は、値を変更してもコンポーネントが更新されていないからです。
つまり、画面の値を変更するには、コンポーネントの再実行が必要となります。
けれど、もしこのCounterを再実行できても、最初にnumを初期化してしまっているのでまた0が表示されてしまいます。
このように、画面の変更には、変更した値もどこかに保持する必要があります。
そして、その役割を果たすのがStateとなります。
Stateの使い方
では次に、具体的なStateの使い方を解説していきます。
まず、先ほどのCounterコンポーネントをStateを使って書き換えると、次のようになります。
const Counter = () => {
const [num,setNum] = useState(0)
const onClickButton = () => {
setNum(num+1)
console.log(num)
}
return (
<>
{num}
<button onClick={onClickButton}>+1</button>
</>
)
}
最初に、useStateを使うことで、stateを定義することができます。
このuseStateに初期値にしたい値を設定することで、初期値とStateの更新用関数が配列の形で返ってきます。
そして、更新用関数に更新後の値を入れることで、値を保持しつつコンポーネントの再実行をすることができます。
stateを使う際の注意点
次に、stateを使う際の注意点をいくつか紹介していきます。
まず、stateの更新は非同期で行われるので、即座に実行はされません。
例えば、次のように記述した場合は、飽くまで0+1を2回実行しているに過ぎないので、表示される値は1になります。
const Counter = () => {
const [num,setNum] = useState(0)
const onClickButton = () => {
setNum(num+1)
setNum(num+1)
console.log(num)
}
return (
<>
{num}
<button onClick={onClickButton}>+1</button>
</>
)
}
もし、上記のような処理をしたいときは、setStateにコールバック関数を渡すことで解決します。
const onClickButton = () => {
setNum(num+1)
setNum((prevState) => (prevState + 1))
console.log(num)
}
コールバック関数の引数として渡ってくるprevStateは、更新後の値が入ってくるので想定通りに2が表示されるようになります。
あと、注意する点についてはStateがオブジェクトの場合は、新しいオブジェクトを作って更新用関数に渡す必要があります。
例えば、以下のようにした場合、再描画はされません。
const Counter = () => {
const [num,setNum] = useState({value: 0})
const onClickButton = () => {
num.value += 1
setNum(num)
console.log(num)
}
return (
<>
{num.value}
<button onClick={onClickButton}>+1</button>
</>
)
}
理由は、オブジェクトの値が変更されていた場合でも、メモリ上は一緒の参照先になるので、ReactがStateの変化が起きたと検知できないためです。
なので、Stateにオブジェクトを使う場合は、新たなオブジェクトを作成してそれを更新用関数に渡す必要があります。
最後に、Stateの管理方法についての注意点です。
Reactの内部では、Stateを変数名ではなく、単に順番を元に管理しています。
つまり、Stateが複数あった場合も、n番目の値に何が入っているかという感じで管理しています。
なので次のように、描画毎でStateの数が変わってくるとエラーが発生します。
const [num,setNum] = useState({value: 0})
if(num === 1){
const [num2,setNum2] = useState({value: 0})
}
またstateは、コンポーネント コンポーネントの場所 + 順番によって管理されるので、同じ場所で同じコンポーネントの表示を切り替えてる場所があった場合、Stateは変更後のコンポーネントに受け継がれます。
const App =(props) => {
const [toggle,setToggle] = useState(false)
return (
<div className="App">
<button onClick={() => setToggle(!toggle)}>切り替え</button>
{toggle ? <Counter name={"counterA"} /> : <Counter name={"counterB"} />}
</div>
);
}
これを防ぎたい場合は、コンポーネントの属性にkeyを違う値で設定すれば防げます。
{toggle ? <Counter key={"counterA"} name={"counterA"} /> : <Counter key={"counterB"} name={"counterB"} />}
keyはReactがコンポーネントを識別できるようにする属性になります。
ただ、このように全く同じコンポーネントを全く同じ場所で切り替えることはほぼないので、頭の片隅おいておけばOKです。
ちなみに、トグルなどでコンポーネントがアンマウント(非表示)された場合、Stateはリセットされます。
もしリセットを防ぎたい時は、親コンポーネントでStateを定義しておく必要があります。
コンポーネントについて補足
最後にコンポーネントについて、いくつか補足情報をお伝えしていきます。
まずコンポーネントは、次のことが起こると再実行されます。
- 親コンポーネントの更新
- Stateの更新
- Propsの更新
これを知っていると、Reactの挙動が理解しやすくなるかと思います。
また、JSXでリストを書くときは、keyをつける必要があります。
Stateと同じように、コンポーネントも飽くまで場所でのみ管理されています。
なので、リストにキーをつけていないと、同じ場所に同じコンポーネントがあることになり、Reactが区別できなくなってしまうからです。
ちなみに、エラーにはなりませんが、keyにインデックスを使用してはいけません。
理由は、レンダリング毎に、keyの値が変わってしまう可能性があるからです。
例えば、3つのリストの最初に新たな要素が足された場合は、全ての要素のkeyの値が変わってしまいます。
なので結局Reactが要素の識別ができなくなってしまいます。
const List = () => {
const arr = ["hoge","foo","bar"]
return (
<>
{arr.map(item =>
<p key={item}>item</p>
)}
</>
)
}
また、createPortlalでDOMを書き換えて、modalなどを表示することができます。
実際の使い方は次のようになります。
const ModalPodal = () => {
const target = document.getElementById("hoge")
console.log(target,"ModalPodal")
return createPortal("hello",target);
}
const App =(props) => {
const [toggle,setToggle] = useState(false)
return (
<div id="test">
<div id="hoge"></div>
<button onClick={() => setToggle(!toggle)}>切り替え</button>
<List />
{toggle && <ModalPodal />}
</div>
);
}
createPortalの第一引数に入れたい要素や文字列、第二引数に対象のDOMを設定することで、特定のDOMに要素を付与することができます。
ちなみに、イベントのバブリングはDOMツリーではなく、JSXによって作られるReactツリーを元に発生します。
Reactの書き方
まずは試しに今開いているサンプルページを少し触ってみましょう。

{プロジェクト名}/src/App.tsx
を開き、19行目の文字をHello World!
にしてみましょう。
保存するとターミナルに文字が走り、自動的にページが更新されるはずです。

このように、Reactではホットリロードという自動更新機能がデフォルトで導入されています。
tsxファイル
次に.tsxというファイルについて簡単に説明します。
先程App.tsxという名前のファイルを編集しました。見慣れない拡張子だと思いますが、これは「React特有の書き方を利用したファイル」という意味になります。(JavaScriptの場合.jsxとなります)
特徴としては、関数の返り値にHTMLを記載するところが他の記法との大きな違いになります。
Reactの考えとしては「ロジック(JavaScript)とマークアップ(HTML)を別々に書く」従来の技術の分離ではなく、「ロジック(JavaScript)とマークアップ(HTML)を機能ごとにひとまとめにする」という関心の分離を採用しているため、このような記法になります。
コンポーネントとは
Reactについて調べていると、しばしば「コンポーネント」という単語を目にします。
コンポーネントとはロジックとマークアップを両方含む疎結合の部品を指します。
つまり、同じ機能を必要な場所で何度も再利用できるように機能ごとに分離して管理するという考え方です。
ページの余白等を決めるコンポーネント
↓
ページに含まれるコンテンツのコンポーネント
↓
コンテンツに含まれるアイテムコンポーネント
と言ったように、分離を行います。

メリット
- 再利用性の向上
- 可読性の向上
- 保守性の向上
例えば、ボタンというコンポーネントを定義した場合は、フォーム以外にも様々なところで再利用ができます。
また、コンポーネント1つ1つはそこまでコードが長くならないので、可読性が向上します。
そして、コンポーネント1つ1つは、基本的に互いに影響を及ぼし合いません。
例えば、ボタンコンポーネントを変更しても、インプットエリアへは何の影響も与えません。
つまり、保守性も向上します。
このように、コンポーネント指向の言語は様々なメリットがあるので、最近ではよく使われているのです。
とりあえず書いてみる
実際に動くコードを作ってみます。
まずは先程見たApp.tsx
の中身をシンプルなものにしてみましょう。
function App() {
return (
<div className="App">
<h1>Hello World!</h1>
</div>
);
}
export default App;
画面を見るとただ「Hello World!」と白い画面に表示されています。
先程話題に出たように、関数の返り値がHTMLになっていることが分かりやすく見えると思います。
変数の利用
このように書き換えてみましょう
function App() {
const text: string = 'Hello World!';
return (
<div className="App">
<h1>{text}</h1>
</div>
);
}
export default App;
画面を見ると何も変化がないことがわかると思います。
上記のように、変数をHTML内に入れられるのも.tsx
の特徴です。
ルーティング
次はボタンを押したら画面が遷移されるようにしたいと思います。
まずは下記のルーティングライブラリをインストールします。
$ npm i react-router-dom
まずApp.tsxを下記のように変更します。
App.tsx
import { Link } from "react-router-dom";
function App() {
const title: string = "Hello World!";
return (
<div className="App">
<h1>{title}</h1>
<Link to='/test'>
ボタン
</Link>
</div>
);
}
export default App;
{プロジェクト名}/src/test.tsx
を作成し下記のコードを記述します。
test.tsx
function Test() {
const title: string = "test";
return (
<div className="Test">
<h1>{title}</h1>
</div>
);
}
export default Test;
その後、{プロジェクト名}/src/index.tsx
を下記のように編集します。
ここでルーティングするURLやコンポーネントを指定しています。
index.tsx
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import Test from "./Test";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import reportWebVitals from "./reportWebVitals";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/test" element={<Test />} />
</Routes>
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
画面に戻り、ボタンを押すと画面遷移することがわかると思います。
子コンポーネントとprops
今度はコンポーネント内でコンポーネントを呼び出してみましょう。
コンポーネントの説明で説明したように、コンポーネントは機能を分割したものになります。そのため、例えば画面コンポーネントの中にボタンコンポーネントを呼び出したいという場合は、コンポーネントをコンポーネントの中に呼ぶ、親子関係のような構造が出来上がります。
{プロジェクト名}/src/children/link.tsx
を作成し下記のコードを記述します。
LinkButton.tsx
type LinkButtonProps = {
text: string,
link: string
}
function LinkButton(props: LinkButtonProps) {
return (
<div className="LinkButton">
<Link to={props.link}>
{props.text}
</Link>
</div>
);
}
export default LinkButton;
この時、LinkButton.tsx
にtype
というものを宣言しています。
これは型宣言と呼ばれるもので、この型を利用した場合はオブジェクト型でstring型のtext
とstring型のlink
しかこの変数に入りませんという意味になります。TypeScriptはこうやって型を指定していくことで変な値の出入りを防いでいます。
App.tsx
import LinkButton from "./children/LinkButton";
function App() {
const title: string = "Hello World!";
return (
<div className="App">
<h1>{title}</h1>
<LinkButton text="ボタン" link="/test" />
</div>
);
}
export default App;
次にApp.tsxを下記のように変更します。
画面を見るとルーティングの時と同じように動作しているのが分かります。LinkButton.tsx
は6行目のfunction
の引数に先程作成した型を指定しています。
このコンポーネント関数の引数こそprops
と呼ばれるもので、親コンポーネントから子コンポーネントへ値を受け渡すことが可能になります。
親側で書いた処理を子に渡すことで、子が不要な処理を抱え込まずに済むのがメリットです。
つまり、担当する機能を分割したままにコンポーネントを細かく増やすことができるのです。
React Hooksとstate
まずはこのように「増やす」ボタンを押したらnum
が加算されるように書いてみます。
import LinkButton from "./children/LinkButton";
function App() {
const title: string = "Hello World!";
let num: number = 0;
const increment = () => {
num += 1;
console.log(num);
};
return (
<div className="App">
<h1>{title}</h1>
{num}回押しました。
<LinkButton text="ボタン" link="/test" />
<button type="button" onClick={increment}>増やす</button>
</div>
);
}
export default App;

この書き方では画面の文字が変わらないことが分かります。
Reactでは、値の更新はとある方法で検知させないと画面に反映がされません。
ここで登場するのが状態管理、stateになります。
簡単に説明すると関数の状態を必要な時だけ更新することで、常に最新のHTMLを最低限の処理で返却するという機能です。
いくつか方法がありますが、今回はReact Hooksと呼ばれる機能を利用します。
下記のようにコードを修正してください。
import { useState } from "react";
import LinkButton from "./children/LinkButton";
function App() {
const title: string = "Hello World!";
const [num, setNum] = useState(0);
const increment = () => {
setNum(num + 1);
console.log(num);
};
return (
<div className="App">
<h1>{title}</h1>
{num}回押しました。
<LinkButton text="ボタン" link="/test" />
<button type="button" onClick={increment}>
増やす
</button>
</div>
);
}
export default App;
画面を見ると表示される数字が更新されていることが分かります。
このように、必要な時だけ画面レンダリングを行うことが可能になります。

また、画面右側のconsoleの数字が画面に対して1低いことが気になった方もいるかと思います。
これはstateの更新は一瞬で済むものではなく、多少時間がかかってしまうため即時に変更後の値を取り出すのは難しいことを表しています。
この値が更新されたことを検知する方法もあるのですが、さらに多くのHooksを理解する必要があるため今回は省略します。
state管理に関するHooksについて紹介した記事があるのでそちらも参照していただけると理解が深まるかと思います。
https://qiita.com/r-terao/items/10d6fe6047f1d117b59a
※チュートリアル:React の導入(公式)
Reduxとは?
Reduxは、Reactが扱うUIのstate(状態)を管理をするためのフレームワークです。
Reactではstateの管理するデータフローにFluxを提案していますが、ReduxはFluxの概念を拡張してより扱いやすく設計されています。
React以外にもAngularJSやjQueryなどと併用して使用することもできますが、Reactと使用するのがベターです。
sample.js
class Example extends React.Component {
constructor() {
super();
this.state = {
data: [],
}
this.fetchData = this.fetchData.bind(this);
}
fetchData() {
axios.get('/fetchData').then((res) => {
this.setState({
data: res.data.data,
});
})
}
render() {
return (
<button
onClick={this.fetchData}
>
Fetch Data
</button>
);
}
}
Store
StoreはStateを一括して保存してくれている貯め場の様な場所だと思ってください。
これは1つのプロジェクトにつき1つしか作りません。
上記のコード内には対応する部分はありません。
Reducer
Reducerは初期Stateの宣言、および後述するActionから渡ってきた指令によってSwitch分で分岐しながらStateを変更してくれる存在です。
ReactプロジェクトだとsetState()
をする感覚と同じです。

Action
Actionはその名の通り関数を定義するファイルになります。
Reactでの違いと比べるとこんな感じで、データを取得してきたり、Stateを変更するためのDataの準備をする行動 = Action
といった感覚になります。
公式には「Actionを発行する」とか言いますが、いきなり言われても意味わかりませんよね。。。

Reactにconnect
ここまで出てきているStore
、Reducer
、action
はReduxが持っているものです。
Reactにとっては全く無関係な状態です。
なのでReactとReduxを繋ぐ為にreact-redux
というライブラリを使います。
下記の実装で見ていきます。
実装 & 雛形
少し説明する箇所が多くなりますが、ざっくりと説明していきます。
想定としては、よくあるページのロード → APIからデータの取得 → データおよびビューの更新
です。
1. storeの定義
( 1 ) – createStore()
でReduxのstoreを使うよ!
的な宣言をします。中のcombineReducers
はreducerをまとめたオブジェクトをcombineReducers
を使うことによって2つ以上のReducerをまとめてくれています。applyMiddleware(thunk)
の部分は、まずapplyMiddleware
はRedux用のサードパーティー製のライブラリを使う際、この中で定義してあげます。有名どころだとredux-devtoolsなど入れることが多いです。
そしてその中で定義しているthunk
ですが、これは本来Reduxでは非同期処理に対応していない為、非同期処理を可能にしてくれるライブラリになります。
非同期処理用のパッケージには
- 今回使っているredux-thunk(https://github.com/reduxjs/redux-thunk)
- redux-saga(https://github.com/redux-saga/redux-saga/blob/master/README_ja.md)
- redux-observable(https://github.com/redux-observable/redux-observable)
などがあり、各々メリット、デメリットがあります。
詳細は割愛しますが、今回は一番使いやすいredux-thunk
を使用します。
( 2 ) – 上記で作成したstore
をProvider
内で呼び出します。
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import App from './User/pages/App';
import reducers from './reducers/';
const store = createStore(combineReducers(reducers), applyMiddleware(thunk)); // (1)
ReactDOM.render(
<Provider store={store}> // (2)
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
</Provider>,
document.getElementById('root'),
);
2. reducerでinitialStateの定義
初期ステートを定義します。
上記で説明したReactでいうthis.state={}
の部分のようなものだと思っていてください。
最初はdefault argumentを与え、随時初期ステートを上書いて更新していく形になります。
reducers/post.js
const initState = {
data: [],
};
export default (state = initState, action) => {
const { type, payload } = action;
switch (type) {
default:
return state;
}
}
なお先ほどIndexでcombineReducers
の話がありましたが、2つ以上のReducerを定義する際には以下のようにオブジェクト型にラップしてエクスポートします。
reducers/index.js
import post from './post';
import sample from './sample';
export default {
post,
sample,
};
3. Componentでの呼び出し
ここがReduxとReactの繋がる大きなポイントになります。
( 1 ) – まずReactの際はただコンポーネントをエクスポートするだけでしたが、ReactとReduxを繋げる際はconnect
関数を使います。慣れてない方だと見慣れない構文ですがconnect()(<Component />)
とし括弧の2つ目にコンポーネントを記載します。
これはHOCs(ハイオーダーコンポーネント)、高階関数といいます。今回は割愛します。
(2) – そして括弧の1つ目のmapStateToProps
ですが、ここではStoreにある値を全て参照できます。Reducerで定義して、Storeに保存されている値を全て参照できるので、この中から必要なReducerの値だけを取ってきます。
* mapDispatchToPropsを定義するやり方もありますが、今回は定義しません。
(3) – connectしてきた値はPropsで受け取ることができます。
Post.js
import React from 'react';
import { connect } from 'react-redux';
class Sample extends React.Component {
render() {
return (
<div>
{this.props.data.map(data => data.name)} // (3)
</div>
);
}
}
const mapStateToProps = ({ post }) => post; // (2)
export default connect(mapStateToProps)(Sample) // (1)
4. actionの定義
概念編で見た通り関数を定義します。
その際dispatch
を受け取ってdispatch
内でtype
、payload
定義します。type
にはReducerで分岐させるためのTypeを渡します。payload
には実際のデータを入れます。(実際にはpayloadと言う名前でなくても良いが、payloadが推奨されている)
actions/post.js
import axios from 'axios';
export const FETCH_DATA = 'FETCH_DATA'; // (1)
export const fetchData = () => (dispatch) => {
axios.get('/fetchData').then((res) => {
dispatch({
type: FETCH_DATA,
payload: res.data.data,
});
});
};
5. reducerにてstateの更新
先ほどactionにてエクスポートしたtypeをインポートし、caseで分岐します。
その際にstateをpayloadのデータで上書きます。
reducers/post.js
+ import { FETCH_DATA } from '../actions/post';
const initState = {
data: [],
};
export default (state = initState, action) => {
const { type, payload } = action;
switch (type) {
+ case FETCH_DATA:
+ return {
+ ...state,
+ data: payload
+ };
default:
return state;
}
}
6. Componentにてactionsの呼び出し
あとは、actionで定義した関数を呼んであげるだけです。
今回のやり方だと、connect
するとdispatch
のPropsが渡ってきますので、dispatch
でラップした上で関数を呼んであげましょう。
Post.js
import React from 'react';
import { connect } from 'react-redux';
+ import { fetchData } from '../actions/post';
class Sample extends React.Component {
+ componentDidMount() {
+ this.props.dispatch(fetchData());
+ }
render() {
return (
<div>
{this.props.data.map(data => data.name)}
</div>
);
}
}
const mapStateToProps = ({ post }) => post;
export default connect(mapStateToProps)(Sample)