目次
1. Reactの新規プロジェクトの立ち上げ
2. コンポーネントのプロパティ(props)とステート(state)
3. Class Components と Function Components
4. 条件分岐 (if) と繰り返し (loop)
5. フォームと親子間のデータのやり取り←今ここ
6. コンポーネントのライフサイクル
7. スタイル (準備中)
8. Higher-Order Component (準備中)
9. Portalを利用したモーダル (準備中)
10. refによるエレメントの取得 (準備中)
11. Contextを利用したテーマの変更 (準備中)
今回の学習内容
今回は、
- Reactでのフォームの利用方法
- 親子間でのデータのやりとり
をやっていきます。
YouTubeでの解説動画
YouTubeでも解説しています。
動画で確認したい方はこちらもどうぞ。
【YouTube動画】 未経験から1週間でをマスターするReact入門 #05. フォームと親子間のデータのやり取り
この記事のソースコード
ソースコードはGitHubで公開しています。
今回のコミット一覧↓
フォームの利用
まずはReactでフォームを利用してみます。
Form.js
にフォームを入れます。
このWebアプリでは、言語のリストと追加を行うアプリにしたいので、新しい言語を追加するフォームを作ります。
import { useState } from 'react'; // 追加
export const Form = () => {
const [text, setText] = useState(''); // 追加
const submitForm = (e) => { // 追加
e.preventDefault();
console.log(`submitForm(${text})`);
}
return (
<div>
{ /* 変更 */ }
<h4>新しい言語の追加</h4>
<form onSubmit={submitForm}>
<div>
<input type="text" value={text} onChange={(e) => setText(e.target.value)} />
</div>
<div>
<button>追加</button>
</div>
</form>
</div>
)
}
コードの説明
const [text, setText] = useState(''); // 追加
まずここで、 text
という state を追加しています。
const submitForm = (e) => { // 追加
e.preventDefault();
console.log(`submitForm(${text})`);
}
次に、 form
をサブミットされたときの関数を定義しました。
ここでは、 preventDefault()
をしてコンソールにログを表示するようにしています。
<h4>新しい言語の追加</h4>
<form onSubmit={submitForm}>
<div>
<input type="text" value={text} onChange={(e) => setText(e.target.value)} />
</div>
<div>
<button>追加</button>
</div>
</form>
form
タグに onSubmit
を定義しています。これで form
がサブミットされると 先程定義した submitForm
関数が呼び出されます。
<input type="text" value={text} onChange={(e) => setText(e.target.value)} />
次にこの input
タグですが、これは text
state を値としてもち、onChange
を利用することで変更検知を行って text
stateを setText
を行うことで変更しています。
こうすることで、 text
を常に input
の内容と一致させることができます。
実際に動かしてみると下図のようになります。
ここまでのコミット
親子間のデータのやりとり
次に、フォームに入力されるとリスト側の言語が増えるようにしてみましょう。
今は List.js
が言語データを管理しているのdせうが、言語データを App.js
が管理するようにします。
そこでまず、前回 List.js
で定義していた LANGUAGE
定数を別ファイル( src/const/languages.js
)に移します。
export const LANGUAGES = [
'JavaScript',
'C++',
'Ruby',
'Java',
'PHP',
'Go'
];
それを利用して、 App.js
を修正します。
import { useState } from 'react';
import { List } from "./List";
import { Form } from "./Form";
import { LANGUAGES } from "./const/languages"; // 追加
function App() {
const [tab, setTab] = useState('list');
const [langs, setLangs] = useState(LANGUAGES); // 追加
return (
<div>
<header>
<ul>
<li onClick={() => setTab('list')}>リスト</li>
<li onClick={() => setTab('form')}>フォーム</li>
</ul>
</header>
<hr />
{
tab === 'list' ? <List /> : <Form />
}
</div>
);
}
export default App;
言語データを管理するために langs
という state を定義しました。
Form.js => App.js のデータのやり取り
次に、子コンポーネントである Form.js
から App.js
へのデータの受け渡しをします。
子から親へのデータの受け渡しは、 props
を利用します。
具体的には、props
に関数への参照を渡すことで、 子コンポーネントからその関数を呼び出してもらいます。
import { useState } from 'react';
import { List } from "./List";
import { Form } from "./Form";
import { LANGUAGES } from "./const/languages";
function App() {
const [tab, setTab] = useState('list');
const [langs, setLangs] = useState(LANGUAGES);
const addLang = (lang) => { // 追加
console.log(lang);
setLangs([...langs, lang])
}
return (
<div>
<header>
<ul>
<li onClick={() => setTab('list')}>リスト</li>
<li onClick={() => setTab('form')}>フォーム</li>
</ul>
</header>
<hr />
{
tab === 'list' ? <List /> : <Form onAddLang={addLang}/> // 変更
}
</div>
);
}
export default App;
App.js
側に addLang
関数を作成し、 Form.js
のプロパティとして渡してみました。
これを Form.js
から呼び出してみます。
import { useState } from 'react';
export const Form = ({ onAddLang }) => { // 変更
const [text, setText] = useState('');
const submitForm = (e) => {
e.preventDefault();
onAddLang(text); // 変更
}
return (
<div>
<h4>新しい言語の追加</h4>
<form onSubmit={submitForm}>
<div>
<input type="text" value={text} onChange={(e) => setText(e.target.value)} />
</div>
<div>
<button>追加</button>
</div>
</form>
</div>
)
}
コード解説
Form.js
では、 onAddLang
という props
を追加しています。これは関数への参照になります。
submitForm
関数内で onAddLang
関数を呼び出すことにより、 App.js
でイベントを起こします。
App.js
では、
<Form onAddLang={addLang}/>
と定義していますので、 Form.js
から onAddLang
が呼ばれると、 App.js
内ので addLang
関数が呼ばれることになります。
const addLang = (lang) => { // 追加
console.log(lang);
setLangs([...langs, lang])
}
addLang
関数では、 App.js
の langs
に対してデータを追加するようになっているので、データが追加されます。
実際に動かしてみる
実際に動かしてみて、 Form.js
から App.js
の関数が呼ばれていることを確認します。
今は App.js
内でコンソールに渡された値を表示することで確認できます。
追加された言語をリストへ反映
次に、追加された言語を List.js
に反映してみます。
import { useState } from 'react';
import { List } from "./List";
import { Form } from "./Form";
import { LANGUAGES } from "./const/languages";
function App() {
const [tab, setTab] = useState('list');
const [langs, setLangs] = useState(LANGUAGES);
const addLang = (lang) => {
setLangs([...langs, lang]);
setTab('list'); // 追加
}
return (
<div>
<header>
<ul>
<li onClick={() => setTab('list')}>リスト</li>
<li onClick={() => setTab('form')}>フォーム</li>
</ul>
</header>
<hr />
{
tab === 'list' ? <List langs={langs} /> : <Form onAddLang={addLang}/> // 変更
}
</div>
);
}
export default App;
フォームから言語が追加されたら List.js
を表示するために、addLang
関数で追加されたらタブも変更するようにしました。
また、 List.js
に langs
stateを渡すようにしています。
次に、 List.js
でこの渡された langs
を利用するようにしましょう。
export const List = ({ langs }) => { // 変更
return (
<div>
{
langs.map((lang, index) => { // 変更
return <div key={index}>{ lang }</div>
})
}
</div>
)
}
List.js
からは、 src/const/languages.js
に移動した LANGUAGES
を削除しました。
また、 props
から langs
を受け取り、それを利用するようにしています。
これにより、下図のようにフォームで追加された内容が List.js
に反映されるようになりました。
今日やったこと
JSXでのフォームの利用
<form onSubmit={submitFunc}>
<input type="text" value={text} onChange={(e) => setText(e.target.value)} />
<button>ボタン</button>
</form>
JSXでフォームを利用するためには、 onSubmit
イベントで関数を呼び出します。
input
属性は、 value
と onChange
を利用して状態を管理します。
親子間のデータのやり取り
子コンポーネント=>親コンポーネント
function Parent() {
const testFunc = () => {}
return <Child parentFunc={testFunc} />
}
function Child({ parentFunc }) {
return <div onClick={() => parentFunc(text)}>テスト</div>
}
子コンポーネントから親コンポーネントにデータを渡すには、 props
に渡された関数を子コンポーネントから呼び出すようにします。
親コンポーネント=>子コンポーネント
function Parent() {
const test = 'テストデータ';
return <Child parentData={test} />
}
function Child({ parentData }) {
return <div>{ parentData }</div>
}
親コンポーネントから子コンポーネントにデータを渡すには、 props
でデータを渡します。
Class Components
を追加しています。 ファイルを追加
Class Components でのコードはこちら
App.js
import React from 'react';
import { List } from "./List";
import { Form } from "./Form";
import { LANGUAGES } from "./const/languages";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
tab: 'list',
langs: LANGUAGES,
};
}
addLang(lang) {
this.setState({
langs: [...this.state.langs, lang],
tab: 'list',
});
}
render() {
const { tab, langs } = this.state;
return (
<div>
<header>
<ul>
<li onClick={() => this.setState({ tab: 'list' })}>リスト</li>
<li onClick={() => this.setState({ tab: 'form' })}>フォーム</li>
</ul>
</header>
<hr />
{
tab === 'list' ? <List langs={langs} /> : <Form onAddLang={(lang) => this.addLang(lang)}/>
}
</div>
)
}
}
export default App;
Form.js
Form.js
は全体的に変更します。
this
のことをケアしてアロー関数で書くことに注意してください。import React from 'react';
export class Form extends React.Component {
constructor(props) {
super(props);
this.state = { text: '' }
}
submitForm(e) {
e.preventDefault();
this.props.onAddLang(this.state.text);
}
render() {
const { text } = this.state;
return (
<div>
<h4>新しい言語の追加</h4>
<form onSubmit={(e) => this.submitForm(e)}>
<div>
<input type="text" value={text} onChange={(e) => this.setState({ text: e.target.value })} />
</div>
<div>
<button>追加</button>
</div>
</form>
</div>
)
}
}
List.js
import React from 'react';
// LANGUAGES定数を削除
export class List extends React.Component {
render() {
const { langs } = this.props; // propsからlangsを利用
return (
<div>
{
langs.map((lang, index) => {
return <div key={index}>{ lang }</div>
})
}
</div>
)
}
}
languages.js
export const LANGUAGES = [
'JavaScript',
'C++',
'Ruby',
'Java',
'PHP',
'Go'
];
こちらのコミットの方が変更点がわかりやすく良いかもしれません。
おわりに
これで、 Form.js
⇒ App.js
の子コンポーネントから親コンポーネントへのデータ渡し、および App.js
⇒ List.js
の親コンポーネントから子コンポーネントへのデータ渡しを実装できました。
次の記事
React入門 未経験から1週間でReactをマスターする #06. コンポーネントのライフサイクル
https://qiita.com/yassun-youtube/items/545e7d9c98fe919dc394