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
]);

react javascript