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 请求父组件传递新值
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