React/フック
をテンプレートにして作成
開始行:
[[FrontPage]]
*目次 [#d92fec5f]
#contents
*useState [#s98aff1c]
-関数コンポーネントでStateを使用するためにはuseState関数...
const [stateを格納する変数, stateの値を更新する関数] = u...
Counter.js
#highlightjs(javascript)
import { useState } from 'react';
export default function Counter({ init }) {
const [count, setCount] = useState(init);
return (
<>
<p>{ count }</p>
<button onClick={ () => setCount( c => c + 1 ) ...
</>
);
}
-Form
--onChange属性を使用すると値の変更がされたときにハンドラ...
#highlightjs(javascript)
export default function UserForm() {
const [form, setForm] = useState({
name: '',
email: ''
});
const formHandler = e => {
setForm({
...form,
[e.target.name]: e.target.value
})
};
return (
<form>
<p>User: {form.name}</p>
<p>Email: {form.email}</p>
<div>
<label htmlFor="name">Name</label>
<input id="name" name="name" type="text"
onChange={formHandler} value={form...
</div>
<div>
<label htmlFor='email'>E-mail</label>
<input id="email" name="email" type="email"
onChange={formHandler} value={form...
</div>
<div>
<button type="button" onClick={ () => ale...
送信
</button>
</div>
</form>
);
}
*useRef [#jd31ce52]
-Stateは更新時にDOMの再描画が行われるが,再描画を行いたく...
-Refは`useRef(初期値)`で宣言可能で,`ref変数.current = xx...
-Refで宣言された変数は要素が再描画された場合でも変数の中...
#highlightjs(javascript)
export default function Counter() {
// countRefの値が変更されても再描画はされない
const countRef = useRef(0);
const handleClick = () => {
// Ref変数.currentで値にアクセスできる
countRef.current = countRef.current + 1;
};
return (
<>
<button onClick={handleClick}>Count++</button>
<button onClick={() => alert(countRef.current...
</>
);
}
*useReducer [#wac78543]
-State同様に値を保持する
-Actionを用いたセッターを使用
-複雑なセッターが複数個ある場合にロジックを1箇所にまとめ...
-useReducer関数を使用してStateとReducerを呼び出すためのdi...
-Reducer
--Stateの更新の際に呼ばれる関数
--保持されているStateと更新時のdispatch関数に渡すActionオ...
--Reducerに渡されるStateは読み取り専用であるため更新をし...
-Dispatch関数
--typeプロパティとReducerに渡したい値を含んだActionオブジ...
#highlightjs(javascript)
useReducer(
reducer,
initialArg,
init?
)
-initialArg: Stateの初期値になる値(3つ目の引数[関数]を指...
-init?: オプション.Stateの初期値を関数によって決定したい...
#highlightjs(javascript)
export default function Counter({init = 0}) {
const [count, dispatch] = useReducer(
(count, action) => {
switch (action.type) {
case 'increment':
return count + 1;
case 'reset':
return init;
default:
throw Error('Unknown action: ' + acti...
}
},
init
);
return (
<>
<p>{count}</p>
<button onClick={() => dispatch({type: 'incre...
<button onClick={() => dispatch({type: 'reset...
</>
);
}
少し複雑な例~
App.js
#highlightjs(javascript)
import {useReducer} from "react";
import AddNote from "./AddNote";
import NoteList from "./NoteList";
let initialNotes = [];
function notesReducer(notes, action) {
switch (action.type) {
case 'added': {
return [...notes, {
id: crypto.randomUUID(),
text: action.text,
}];
}
case 'edited': {
return notes.map( e => {
return e.id === action.note.id ? action.note : e;
});
}
case 'deleted': {
return notes.filter( e => e.id !== action.id);
}
default: {
throw Error('Unknown action: ' + action.type);
}
}
}
export default function App() {
const [notes, dispatch] = useReducer(
notesReducer,
initialNotes
);
// ノートを追加
function handleAddNote(text) {
dispatch({
type: 'added',
text: text,
});
}
// ノートを編集
function handleEditNote(note) {
dispatch({
type: 'edited',
note: note,
});
}
// ノートを削除
function handleDeleteNote(id) {
dispatch({
type: "deleted",
id: id,
});
}
return (
<>
<h1>Notes</h1>
<AddNote onAddNote={handleAddNote}/>
<NoteList
notes={notes}
onEditNote={handleEditNote}
onDeleteNote={handleDeleteNote}
/>
</>
);
}
AddNote.js
#highlightjs(javascript)
import {useState} from "react";
export default function AddNote({onAddNote}) {
const [text, setText] = useState('');
return (
<>
<input
placeholder="ノートを追加"
value={text}
onChange={e => setText(e.target.value)}
/>
<button onClick={() => {
onAddNote(text);
setText('');
}}>追加</button>
</>
);
}
NoteList.js
#highlightjs(javascript)
import {useState} from "react";
export default function NoteList({
notes,
onEditNote,
onDeleteNote,
}) {
return (
<>
{notes.map(e => (
<div key={e.id}>
<NoteRow
note={e}
onEdit={onEditNote}
onDelete={onDeleteNote}
/>
</div>
))}
</>
);
}
function NoteRow({
note,
onEdit,
onDelete
}) {
const [isEditing, setIsEditing] = useState(false);
if (isEditing) {
return (
<>
<input
value={note.text}
onChange={e => {
onEdit({
...note,
text: e.target.value
});
}} />
<button onClick={() => setIsEditing(false...
保存
</button>
</>
);
}
else {
return (
<>
{note.text}
<button onClick={() => setIsEditing(true)}>
編集
</button>
<button onClick={() => onDelete(note.id)}>
削除
</button>
</>
);
}
}
*useContext [#sb873fdb]
-上位のコンポーネントの値にアクセスするためのフック
-createContext関数でContextオブジェクトを定義
-useContext関数で上位コンポーネントで定義されたContextオ...
-`Contextオブジェクト.Provider`コンポーネント以下の子コン...
const Contextオブジェクト = createContext(defaultValue);
const 値 = useContext(Contextオブジェクト);
#highlightjs(javascript)
import {createContext, useContext} from "react";
export const MessageContext = createContext('hello');
export default function Context() {
return (
<>
{/* Context.Provider以下のコンポーネントではv...
<MessageContext.Provider value='hello world'>
<Label /> {/* 'hello world'が描画される */}
</MessageContext.Provider>
{/* Context.Provider以下のコンポーネントでな...
<Label /> {/* defaultValueの'hello'が描画され...
</>
);
}
function Label() {
return <Message />
}
function Message() {
const message = useContext(MessageContext);
return <p>{message}</p>
}
*useEffect [#a0bc88a8]
-主に外部のAPI等を呼び出す処理を記述する
-コンポーネントがレンダリングされたあとに処理を実行する
-useEffect関数の返り値はundefinedを返す
useEffect(setup, dependencies?)
-setupに呼び出したい処理(関数)を指定する
-dependenciesは省略可能
--省略した場合はコンポーネントの再レンダリングのたびにset...
--空配列にした場合はコンポーネントの初期描画時にのみsetup...
--変数群を指定(1つの場合でも配列で指定する)した場合は,...
#highlightjs(javascript)
import {useEffect, useState} from "react";
export default function Weather({latitude='35.662422', l...
const [data, setData] = useState(null);
useEffect(() => {
fetch(`https://api.open-meteo.com/v1/forecast?lat...
.then(response => response.json())
.then(json => setData(`time:${json.current.ti...
}, []);
if (!data) {
return <p>Loading...</p>
}
return <p>{data}</p>
}
**アンマウント時の処理 [#fd0696e5]
-第一引数の関数の戻り値として関数を返すようにすると,アン...
useEffect(() => {
起動と再描画時に実行
return () => {
アンマウント時に実行
}
}, [トリガー変数]);
**更新処理 [#aaf30169]
-dependenciesに更新用のフラグを使用することで,APIからデ...
#highlightjs(javascript)
import {useEffect, useState} from "react";
export default function Weather({latitude='35.662422', l...
const [data, setData] = useState(null);
const [refresh, setRefresh] = useState(false);
useEffect(() => {
fetch(`https://api.open-meteo.com/v1/forecast?lat...
.then(response => response.json())
.then(json => {
console.log('update');
setRefresh(false);
setData(`time:${json.current.time}, tempe...
});
}, [refresh]);
if (!data) {
return <p>Loading...</p>
}
return (
<>
<p>{data}</p>
<button onClick={() => setRefresh(true)}>更新...
</>
);
}
終了行:
[[FrontPage]]
*目次 [#d92fec5f]
#contents
*useState [#s98aff1c]
-関数コンポーネントでStateを使用するためにはuseState関数...
const [stateを格納する変数, stateの値を更新する関数] = u...
Counter.js
#highlightjs(javascript)
import { useState } from 'react';
export default function Counter({ init }) {
const [count, setCount] = useState(init);
return (
<>
<p>{ count }</p>
<button onClick={ () => setCount( c => c + 1 ) ...
</>
);
}
-Form
--onChange属性を使用すると値の変更がされたときにハンドラ...
#highlightjs(javascript)
export default function UserForm() {
const [form, setForm] = useState({
name: '',
email: ''
});
const formHandler = e => {
setForm({
...form,
[e.target.name]: e.target.value
})
};
return (
<form>
<p>User: {form.name}</p>
<p>Email: {form.email}</p>
<div>
<label htmlFor="name">Name</label>
<input id="name" name="name" type="text"
onChange={formHandler} value={form...
</div>
<div>
<label htmlFor='email'>E-mail</label>
<input id="email" name="email" type="email"
onChange={formHandler} value={form...
</div>
<div>
<button type="button" onClick={ () => ale...
送信
</button>
</div>
</form>
);
}
*useRef [#jd31ce52]
-Stateは更新時にDOMの再描画が行われるが,再描画を行いたく...
-Refは`useRef(初期値)`で宣言可能で,`ref変数.current = xx...
-Refで宣言された変数は要素が再描画された場合でも変数の中...
#highlightjs(javascript)
export default function Counter() {
// countRefの値が変更されても再描画はされない
const countRef = useRef(0);
const handleClick = () => {
// Ref変数.currentで値にアクセスできる
countRef.current = countRef.current + 1;
};
return (
<>
<button onClick={handleClick}>Count++</button>
<button onClick={() => alert(countRef.current...
</>
);
}
*useReducer [#wac78543]
-State同様に値を保持する
-Actionを用いたセッターを使用
-複雑なセッターが複数個ある場合にロジックを1箇所にまとめ...
-useReducer関数を使用してStateとReducerを呼び出すためのdi...
-Reducer
--Stateの更新の際に呼ばれる関数
--保持されているStateと更新時のdispatch関数に渡すActionオ...
--Reducerに渡されるStateは読み取り専用であるため更新をし...
-Dispatch関数
--typeプロパティとReducerに渡したい値を含んだActionオブジ...
#highlightjs(javascript)
useReducer(
reducer,
initialArg,
init?
)
-initialArg: Stateの初期値になる値(3つ目の引数[関数]を指...
-init?: オプション.Stateの初期値を関数によって決定したい...
#highlightjs(javascript)
export default function Counter({init = 0}) {
const [count, dispatch] = useReducer(
(count, action) => {
switch (action.type) {
case 'increment':
return count + 1;
case 'reset':
return init;
default:
throw Error('Unknown action: ' + acti...
}
},
init
);
return (
<>
<p>{count}</p>
<button onClick={() => dispatch({type: 'incre...
<button onClick={() => dispatch({type: 'reset...
</>
);
}
少し複雑な例~
App.js
#highlightjs(javascript)
import {useReducer} from "react";
import AddNote from "./AddNote";
import NoteList from "./NoteList";
let initialNotes = [];
function notesReducer(notes, action) {
switch (action.type) {
case 'added': {
return [...notes, {
id: crypto.randomUUID(),
text: action.text,
}];
}
case 'edited': {
return notes.map( e => {
return e.id === action.note.id ? action.note : e;
});
}
case 'deleted': {
return notes.filter( e => e.id !== action.id);
}
default: {
throw Error('Unknown action: ' + action.type);
}
}
}
export default function App() {
const [notes, dispatch] = useReducer(
notesReducer,
initialNotes
);
// ノートを追加
function handleAddNote(text) {
dispatch({
type: 'added',
text: text,
});
}
// ノートを編集
function handleEditNote(note) {
dispatch({
type: 'edited',
note: note,
});
}
// ノートを削除
function handleDeleteNote(id) {
dispatch({
type: "deleted",
id: id,
});
}
return (
<>
<h1>Notes</h1>
<AddNote onAddNote={handleAddNote}/>
<NoteList
notes={notes}
onEditNote={handleEditNote}
onDeleteNote={handleDeleteNote}
/>
</>
);
}
AddNote.js
#highlightjs(javascript)
import {useState} from "react";
export default function AddNote({onAddNote}) {
const [text, setText] = useState('');
return (
<>
<input
placeholder="ノートを追加"
value={text}
onChange={e => setText(e.target.value)}
/>
<button onClick={() => {
onAddNote(text);
setText('');
}}>追加</button>
</>
);
}
NoteList.js
#highlightjs(javascript)
import {useState} from "react";
export default function NoteList({
notes,
onEditNote,
onDeleteNote,
}) {
return (
<>
{notes.map(e => (
<div key={e.id}>
<NoteRow
note={e}
onEdit={onEditNote}
onDelete={onDeleteNote}
/>
</div>
))}
</>
);
}
function NoteRow({
note,
onEdit,
onDelete
}) {
const [isEditing, setIsEditing] = useState(false);
if (isEditing) {
return (
<>
<input
value={note.text}
onChange={e => {
onEdit({
...note,
text: e.target.value
});
}} />
<button onClick={() => setIsEditing(false...
保存
</button>
</>
);
}
else {
return (
<>
{note.text}
<button onClick={() => setIsEditing(true)}>
編集
</button>
<button onClick={() => onDelete(note.id)}>
削除
</button>
</>
);
}
}
*useContext [#sb873fdb]
-上位のコンポーネントの値にアクセスするためのフック
-createContext関数でContextオブジェクトを定義
-useContext関数で上位コンポーネントで定義されたContextオ...
-`Contextオブジェクト.Provider`コンポーネント以下の子コン...
const Contextオブジェクト = createContext(defaultValue);
const 値 = useContext(Contextオブジェクト);
#highlightjs(javascript)
import {createContext, useContext} from "react";
export const MessageContext = createContext('hello');
export default function Context() {
return (
<>
{/* Context.Provider以下のコンポーネントではv...
<MessageContext.Provider value='hello world'>
<Label /> {/* 'hello world'が描画される */}
</MessageContext.Provider>
{/* Context.Provider以下のコンポーネントでな...
<Label /> {/* defaultValueの'hello'が描画され...
</>
);
}
function Label() {
return <Message />
}
function Message() {
const message = useContext(MessageContext);
return <p>{message}</p>
}
*useEffect [#a0bc88a8]
-主に外部のAPI等を呼び出す処理を記述する
-コンポーネントがレンダリングされたあとに処理を実行する
-useEffect関数の返り値はundefinedを返す
useEffect(setup, dependencies?)
-setupに呼び出したい処理(関数)を指定する
-dependenciesは省略可能
--省略した場合はコンポーネントの再レンダリングのたびにset...
--空配列にした場合はコンポーネントの初期描画時にのみsetup...
--変数群を指定(1つの場合でも配列で指定する)した場合は,...
#highlightjs(javascript)
import {useEffect, useState} from "react";
export default function Weather({latitude='35.662422', l...
const [data, setData] = useState(null);
useEffect(() => {
fetch(`https://api.open-meteo.com/v1/forecast?lat...
.then(response => response.json())
.then(json => setData(`time:${json.current.ti...
}, []);
if (!data) {
return <p>Loading...</p>
}
return <p>{data}</p>
}
**アンマウント時の処理 [#fd0696e5]
-第一引数の関数の戻り値として関数を返すようにすると,アン...
useEffect(() => {
起動と再描画時に実行
return () => {
アンマウント時に実行
}
}, [トリガー変数]);
**更新処理 [#aaf30169]
-dependenciesに更新用のフラグを使用することで,APIからデ...
#highlightjs(javascript)
import {useEffect, useState} from "react";
export default function Weather({latitude='35.662422', l...
const [data, setData] = useState(null);
const [refresh, setRefresh] = useState(false);
useEffect(() => {
fetch(`https://api.open-meteo.com/v1/forecast?lat...
.then(response => response.json())
.then(json => {
console.log('update');
setRefresh(false);
setData(`time:${json.current.time}, tempe...
});
}, [refresh]);
if (!data) {
return <p>Loading...</p>
}
return (
<>
<p>{data}</p>
<button onClick={() => setRefresh(true)}>更新...
</>
);
}
ページ名: