React の基礎と落とし穴
React の基礎と落とし穴。主に公式のドキュメント からの抜粋。
- React コンポーネントは通常の JavaScript 関数であり、名前は常に大文字で始まる必要があります
function MyButton() {
return (
<button>I'm a button</button>
);
}
- マークアップがすべて return キーワードと同じ行にない場合は、一対の括弧で囲む必要があります
return (
<div>
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
</div>
);
- JSX は HTML よりも厳格であり、タグは常に閉じる必要があります
<img className="avatar" />
<br />
<MyButton />
<h1>This is heading</h1>
<button>I'm a button</button>
//...
- React コンポーネントは、複数の JSX タグを返すことはできません。
<div>...</div>
または空の<>...</>
ラッパーなどの共有の親で囲む必要があります
function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}
- コンポーネントは他のコンポーネントをレンダリングできますが、定義をネストすることはできません
export default function Gallery() {
// 🔴 Never define a component inside another component!
function Profile() {
// ...
}
// ...
}
- CSS クラスは
className
で指定され、インラインstyle
プロパティはcamelCase
で記述する必要があります
<img className="avatar" />
<ul style="background-color: black"> // html
<ul style={{ backgroundColor: 'black' }}> // react
- 中括弧は、JavaScript 変数または式を使用するために JavaScript に
エスケープバック
するために使用されます
const user = {
name: 'Hedy Lamarr',
imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
imageSize: 90,
};
export default function Profile() {
return (
<>
<h1>{user.name}</h1>
<img
className="avatar"
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{
width: user.imageSize,
height: user.imageSize
}}
/>
</>
);
}
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
- 属性に使用する場合、中括弧は
=
の直後に"
を付けてはいけない。また、動的タグの変数として使用することのできない
// src={avatar} OK
// src="{avatar}" NG
// <h1>{name}'s To Do List</h1> OK
// <{tag}>Gregorio Y. Zara's To Do List</{tag}> NG
- オブジェクトを渡すには二重中括弧が必要です
export default function TodoList() {
return (
<ul style={{
backgroundColor: 'black',
color: 'pink'
}}>
<li>Improve the videophone</li>
<li>Prepare aeronautics lectures</li>
<li>Work on the alcohol-fuelled engine</li>
</ul>
);
}
spread
構文を使用して、props を子に転送できます
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}
- props は不変であり、子コンポーネントは
set state
を介して新しい値を渡すように親コンポーネントにask
する必要があります
function Clock({ color, time }) {
return (
<h1 style={{ color: color }}>
{time}
</h1>
);
}
- 親コンポーネントには、内部にネストされたコンテンツに設定された
children
prop があります
<Card>
<Avatar />
</Card>
function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}
function Avatar({ person, size }) {
return (
<img
className="avatar"
src={getImageUrl(person)}
alt={person.name}
width={size}
height={size}
/>
);
}
- 条件付きレンダリングはさまざまな方法で動作します
// with if/else condition
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
// with ternary operator
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
// with shortcut operation
<div>
{isLoggedIn && <AdminPanel />}
</div>
for loop
またはmap
メソッドを使用してリストをレンダリングし、各項目には一意の不変キーが必要です
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
- フックは、コンポーネントまたは他のフックの最上位レベルで呼び出す必要があります
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
- 1 つのイベントで複数の状態を更新するには、updater 関数を使用します
function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);
}}>+3</button>
</>
)
}
spread
構文を使用して、その場で変更するのではなく、状態を設定するためにオブジェクトまたは配列のコピーを作成します
setPerson({
...person, // Copy other fields
artwork: { // but replace the artwork
...person.artwork, // with the same one
city: 'New Delhi' // but in New Delhi!
}
});
setArtists([
{ id: nextId++, name: name },
...artists // Put old items at the end
]);