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
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來請求父元件傳遞新值
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 loopmap 方法渲染列表,列表每個項目必須具有唯一的不可變鍵
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>
  );
}
  • 使用更新函數在一個事件中多次更新某些狀態
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