const [stateを格納する変数, stateの値を更新する関数] = useState(初期値)
Counter.js
import { useState } from 'react';
export default function Counter({ init }) {
const [count, setCount] = useState(init);
return (
<>
<p>{ count }</p>
<button onClick={ () => setCount( c => c + 1 ) }>++</button>
</>
);
}
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.name} />
</div>
<div>
<label htmlFor='email'>E-mail</label>
<input id="email" name="email" type="email"
onChange={formHandler} value={form.email} />
</div>
<div>
<button type="button" onClick={ () => alert(`Hello ${form.name}`)}>
送信
</button>
</div>
</form>
);
}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)}>Show</button>
</>
);
}useReducer( reducer, initialArg, init? )
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: ' + action.type);
}
},
init
);
return (
<>
<p>{count}</p>
<button onClick={() => dispatch({type: 'increment'})}>++</button>
<button onClick={() => dispatch({type: 'reset'})}>reset</button>
</>
);
}
少し複雑な例
App.js
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
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
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>
</>
);
}
}
const Contextオブジェクト = createContext(defaultValue);
const 値 = useContext(Contextオブジェクト);
import {createContext, useContext} from "react";
export const MessageContext = createContext('hello');
export default function Context() {
return (
<>
{/* Context.Provider以下のコンポーネントではvalueの値になる */}
<MessageContext.Provider value='hello world'>
<Label /> {/* 'hello world'が描画される */}
</MessageContext.Provider>
{/* Context.Provider以下のコンポーネントでない場合はdefaultValueが使用される */}
<Label /> {/* defaultValueの'hello'が描画される */}
</>
);
}
function Label() {
return <Message />
}
function Message() {
const message = useContext(MessageContext);
return <p>{message}</p>
}
useEffect(setup, dependencies?)
import {useEffect, useState} from "react";
export default function Weather({latitude='35.662422', longitude='139.590247'}) {
const [data, setData] = useState(null);
useEffect(() => {
fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m&timezone=Asia%2FTokyo&forecast_days=1`)
.then(response => response.json())
.then(json => setData(`time:${json.current.time}, temperature:${json.current.temperature_2m}`));
}, []);
if (!data) {
return <p>Loading...</p>
}
return <p>{data}</p>
}