プロジェクト作成
npx create-react-app react-sample
cd react-sample
npm start または yarn start
コメント
- jsxの中では、
{/* コメント */}
を使う。 - タグの中は、
/* */
//
も使える
クラスコンポーネント
src/App.js
import React, { Component } from "react";
class App extends Component {
render() {
return <p>Hello world {this.props.name}!</p>;
}
}
export default App;
関数コンポーネント
- シンプルだが、State、ライフサイクルメソッドが使えない
- Hookを使うことにより、上記問題は解決する
import React from "react";
const App = (props) => {
return <p>Hello world {props.name}!</p>;
};
export default App;
props
-
<App name="ichiro"></App>
の場合{this.props.name}
=ichiro
-
<App><p>こんにちは</p></App>
の場合{this.props.children}
=<p>こんにちは</p>
繰り返し
import React from "react";
const App = () => {
const users = [{ name: "yamada" }, { name: "suziki" }, { name: "saito" }];
return (
<dl>
{users.map((user, index) => (
<ul key={index}>{user.name}</ul>
))}
</dl>
);
};
export default App;
条件分岐
// 条件演算子
{ this.props.isNew ? <NewIcon /> : null }
// &&演算子
{ this.props.isNew && <NewIcon /> }
// 即時関数
{(() => {
if (this.props.isNew) {
return <NewIcon />
}
})}
stateを使ったフォーム
- constructor()の中で、stateの初期化を行う。
- this.setState()でstateの更新を行う。
import React, { Component } from "react";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
prefecture: "",
career: "",
skill: [""],
memo: "",
};
this.handleChange = this.handleChange.bind(this);
this.handleChangeMulti = this.handleChangeMulti.bind(this);
this.file = React.createRef(); // fileを参照できるようにする(Uncontrolled Component)
this.show = this.show.bind(this);
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
handleChangeMulti(e) {
const fs = this.state.skill;
if (e.target.checked) {
fs.push(e.target.value);
} else {
fs.splice(fs.indexOf(e.target.value), 1);
}
this.setState({
[e.target.name]: fs,
});
}
show() {
console.log(`${this.state.name}`);
console.log(`${this.state.prefecture}`);
console.log(`${this.state.career}`);
console.log(`${this.state.skill}`);
console.log(`${this.state.memo}`);
const f = this.file.current.files[0];
if (f) {
console.log(`${f.name} ${f.type} ${f.size}`);
}
}
render() {
return (
<form>
<label htmlFor="name">名前:</label>
<input id="name" name="name" type="text" value={this.state.name} onChange={this.handleChange}></input>
<br />
<label htmlFor="prefecture">住所:</label>
<select id="prefecture" name="prefecture" value={this.state.prefecture} onChange={this.handleChange}>
<option value=""></option>
<option value="tokyo">東京都</option>
<option value="kanagawa">神奈川県</option>
<option value="saitama">埼玉県</option>
<option value="chiba">千葉県</option>
<option value="ibaraki">茨城県</option>
<option value="gunma">群馬県</option>
<option value="tochigi">栃木県</option>
</select>
<fieldset>
<legend>経験年数:</legend>
<input id="career_zero" name="career" type="radio" value="zero" checked={this.state.career === "zero"} onChange={this.handleChange} />
<label htmlFor="career_zero">未経験</label>
<input id="career_one" name="career" type="radio" value="one" checked={this.state.career === "one"} onChange={this.handleChange} />
<label htmlFor="career_one">1年未満</label>
<input id="career_three" name="career" type="radio" value="three" checked={this.state.career === "three"} onChange={this.handleChange} />
<label htmlFor="career_three">1~3年</label>
<input id="career_five" name="career" type="radio" value="five" checked={this.state.career === "five"} onChange={this.handleChange} />
<label htmlFor="career_five">3年~5年</label>
<input id="career_over" name="career" type="radio" value="over" checked={this.state.career === "over"} onChange={this.handleChange} />
<label htmlFor="career_over">5年以上</label>
</fieldset>
<fieldset>
<legend>スキル:</legend>
<input id="skill_java" name="skill" type="checkbox" value="java" checked={this.state.skill.includes("java")} onChange={this.handleChangeMulti} />
<label htmlFor="skill_java">Java</label>
<input id="skill_php" name="skill" type="checkbox" value="php" checked={this.state.skill.includes("php")} onChange={this.handleChangeMulti} />
<label htmlFor="skill_php">PHP</label>
<input id="skill_javascript" name="skill" type="checkbox" value="javascript" checked={this.state.skill.includes("javascript")} onChange={this.handleChangeMulti} />
<label htmlFor="skill_javascript">Javascript</label>
<input id="skill_python" name="skill" type="checkbox" value="python" checked={this.state.skill.includes("python")} onChange={this.handleChangeMulti} />
<label htmlFor="skill_python">Python</label>
<input id="skill_ruby" name="skill" type="checkbox" value="ruby" checked={this.state.skill.includes("ruby")} onChange={this.handleChangeMulti} />
<label htmlFor="skill_ruby">Ruby</label>
</fieldset>
<br />
<label htmlFor="memo">メモ:</label>
<textarea id="memo" name="memo" value={this.state.memo} onChange={this.handleChange}></textarea>
<br />
<label htmlFor="file">ファイル:</label>
<input id="file" name="file" type="file" ref={this.file}></input>
<br />
<button type="button" onClick={this.show}>
送信
</button>
</form>
);
}
}
useStateを使ったフォーム
import React, { useState } from "react";
const App = () => {
const [name, setName] = useState("");
const [prefecture, setPrefecture] = useState("");
const [career, setCareer] = useState("");
const [skill, setSkill] = useState([]);
const [memo, setMemo] = useState("");
const file = React.createRef();
const handleChange = (event) => {
switch (event.target.name) {
case "name":
setName(event.target.value);
break;
case "prefecture":
setPrefecture(event.target.value);
break;
case "career":
setCareer(event.target.value);
break;
case "memo":
setMemo(event.target.value);
break;
default:
console.log("key not found");
}
};
const handleChangeMulti = (e) => {
if (skill.includes(e.target.value)) {
setSkill(skill.filter((item) => item !== e.target.value));
} else {
setSkill([...skill, e.target.value]);
}
};
const show = () => {
console.log(name);
console.log(prefecture);
console.log(career);
console.log(skill);
console.log(memo);
const f = file.current.files[0];
if (f) {
console.log(`${f.name} ${f.type} ${f.size}`);
}
};
return (
<form>
<label htmlFor="name">名前:</label>
<input id="name" name="name" type="text" value={name} onChange={handleChange}></input>
<br />
<label htmlFor="prefecture">住所:</label>
<select id="prefecture" name="prefecture" value={prefecture} onChange={handleChange}>
<option value=""></option>
<option value="tokyo">東京都</option>
<option value="kanagawa">神奈川県</option>
<option value="saitama">埼玉県</option>
<option value="chiba">千葉県</option>
<option value="ibaraki">茨城県</option>
<option value="gunma">群馬県</option>
<option value="tochigi">栃木県</option>
</select>
<fieldset>
<legend>経験年数:</legend>
<input id="career_zero" name="career" type="radio" value="zero" checked={career === "zero"} onChange={handleChange} />
<label htmlFor="career_zero">未経験</label>
<input id="career_one" name="career" type="radio" value="one" checked={career === "one"} onChange={handleChange} />
<label htmlFor="career_one">1年未満</label>
<input id="career_three" name="career" type="radio" value="three" checked={career === "three"} onChange={handleChange} />
<label htmlFor="career_three">1~3年</label>
<input id="career_five" name="career" type="radio" value="five" checked={career === "five"} onChange={handleChange} />
<label htmlFor="career_five">3年~5年</label>
<input id="career_over" name="career" type="radio" value="over" checked={career === "over"} onChange={handleChange} />
<label htmlFor="career_over">5年以上</label>
</fieldset>
<fieldset>
<legend>スキル:</legend>
<input id="skill_java" name="skill" type="checkbox" value="java" checked={skill.includes("java")} onChange={handleChangeMulti} />
<label htmlFor="skill_java">Java</label>
<input id="skill_php" name="skill" type="checkbox" value="php" checked={skill.includes("php")} onChange={handleChangeMulti} />
<label htmlFor="skill_php">PHP</label>
<input id="skill_javascript" name="skill" type="checkbox" value="javascript" checked={skill.includes("javascript")} onChange={handleChangeMulti} />
<label htmlFor="skill_javascript">Javascript</label>
<input id="skill_python" name="skill" type="checkbox" value="python" checked={skill.includes("python")} onChange={handleChangeMulti} />
<label htmlFor="skill_python">Python</label>
<input id="skill_ruby" name="skill" type="checkbox" value="ruby" checked={skill.includes("ruby")} onChange={handleChangeMulti} />
<label htmlFor="skill_ruby">Ruby</label>
</fieldset>
<br />
<label htmlFor="memo">メモ:</label>
<textarea id="memo" name="memo" value={memo} onChange={handleChange}></textarea>
<br />
<label htmlFor="file">ファイル:</label>
<input id="file" name="file" type="file" ref={file}></input>
<br />
<button type="button" onClick={show}>
送信
</button>
</form>
);
};
export default App;
ライフサイクルメソッド
Mounting | Updating | Unmounting | 用途 | |
---|---|---|---|---|
constructor(props) | 初期化 | stateの初期化、thisの固定など | ||
render() | 描画時 | 描画時 | 必須。React要素、文字列値、数値、など | |
componentDidMount() | 配置後 | リソースの初期化、文書ツリーへのアクセスなど | ||
shouldComponentUpdate() | 再描画前 | 再描画前にアクセスしたいとき | ||
componentDidUpdate() | 再描画後 | 再描画後にアクセスしたいとき | ||
componentWillUnmount() | 破棄時 | リソースの破棄など |
ルーティング
npm install react-router-dom
または
yarn add react-router-dom
import React from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
export default function BasicRouter() {
return (
<Router>
<div>
{/* リンク表示部 リンクがここに表示される */}
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
{/* コンポーネント表示部 パスがマッチングしたコンポーネントがここに表示される */}
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
</div>
);
}
ローカルストレージ
- ローカルストレージ
値 = localStorade.getItem(キー)
localStorade.setItem(キー, 値)
- JSON⇔オブジェクト変換
オブジェクト = JSON.parse(JSON文字列)
JSON文字列 = JSON.stringify(オブジェクト)
-
|| []
はnullの場合、[]
にする。
// データ取得
componentDidMount() {
const todos = JSON.parse(localStorade.getItem('todos')) || [];
this.setState({todos: todos});
}
// データ1件追加
addTodo(todo) {
const todos = this.state.todos;
todos.push(todo);
this.setState({todos: todos});
localStorade.setItem('todos', JSON.stringify(this.state.todos));
}
// データ1件削除
deleteTodo(i) {
const todos = this.state.todos;
todos.splice(i, 1);
this.setState({todos: todos});
localStorade.setItem('todos', JSON.stringify(this.state.todos));
}
Fetch API
Read List
fetch("http://localhost:8080/todos")
.then((res) => res.json())
.then((data) => {
this.setState({todos: data})
})
.catch((err) => console.log(err))
Read
fetch("http://localhost:8080/todos/${id}")
.then((res) => res.json())
.then((data) => {
this.setState({todo: data})
})
.catch((err) => console.log(err))
Create
fetch("http://localhost:8080/todos" ,{
method: "POST",
headers: { "Content-type": "application/json" },
body: JSON.stringify(todo)
})
.then((res) => res.json())
.then((data) => {
// 処理
})
.catch((err) => console.log(err))
Update
fetch("http://localhost:8080/todos/${id}" ,{
method: "PUT",
headers: { "Content-type": "application/json" },
body: JSON.stringify(todos)
})
.then((res) => res.json())
.then((data) => {
// 処理
})
.catch((err) => console.log(err))
Delete
fetch("http://localhost:8080/todos/${id}" ,{
method: "DELETE"
})
.then((res) => res.json())
.then((data) => {
// 処理
})
.catch((err) => console.log(err))
今後追加したいこと
- Redux
- Hook
- Spring Bootなどへの組み込み
参考
速習 React 速習シリーズ Kindle版
https://reactrouter.com/web/guides/quick-start