React 调用组件和钩子

React 负责在必要时渲染组件和 Hooks 以优化用户体验。它是声明式的:你告诉 React 在组件逻辑中渲染什么,React 会决定如何最好地向用户展示它。


切勿直接调用组件函数

🌐 Never call component functions directly

组件应该只在 JSX 中使用。不要像普通函数一样调用它们。React 应该来调用它们。

🌐 Components should only be used in JSX. Don’t call them as regular functions. React should call it.

React 必须决定在 渲染 期间何时调用你的组件函数。在 React 中,你通过使用 JSX 来实现这一点。

🌐 React must decide when your component function is called during rendering. In React, you do this using JSX.

function BlogPost() {
return <Layout><Article /></Layout>; // ✅ Good: Only use components in JSX
}
function BlogPost() {
return <Layout>{Article()}</Layout>; // 🔴 Bad: Never call them directly
}

如果一个组件包含 Hooks,当组件在循环中或有条件地直接调用时,很容易违反 Hooks 规则

🌐 If a component contains Hooks, it’s easy to violate the Rules of Hooks when components are called directly in a loop or conditionally.

让 React 编排渲染还有很多好处:

🌐 Letting React orchestrate rendering also allows a number of benefits:

  • 组件不再仅仅是功能。 React 可以通过与组件在树中的身份绑定的 Hooks,为它们增加像 本地状态 这样的特性。
  • 组件类型参与调和。 通过让 React 调用你的组件,你也向它更多地说明了你的树的概念结构。例如,当你从渲染 <Feed> 页面切换到 <Profile> 页面时,React 不会尝试重用它们。
  • React 可以增强你的用户体验。 例如,它可以让浏览器在组件调用之间执行一些工作,从而使重新渲染大型组件树不会阻塞主线程。
  • 更好的调试体验。 如果组件是库所认知的一等公民,我们就可以在开发中构建丰富的开发者工具用于内部检查。
  • 更高效的调和。 React 可以准确决定树中哪些组件需要重新渲染,并跳过不需要的组件。这让你的应用更快、更流畅。

切勿将钩子作为常规值传递

🌐 Never pass around Hooks as regular values

Hooks 应该只在组件或 Hooks 内部调用。绝不应作为普通值传递。

🌐 Hooks should only be called inside of components or Hooks. Never pass it around as a regular value.

Hooks 允许你用 React 功能增强组件。它们应该始终作为函数调用,绝不应作为常规值传递。这使得 局部推断 成为可能,即开发者可以通过单独查看组件来了解组件能做的所有事情。

🌐 Hooks allow you to augment a component with React features. They should always be called as a function, and never passed around as a regular value. This enables local reasoning, or the ability for developers to understand everything a component can do by looking at that component in isolation.

违反此规则将导致 React 无法自动优化你的组件。

🌐 Breaking this rule will cause React to not automatically optimize your component.

不要动态改变钩子

🌐 Don’t dynamically mutate a Hook

Hooks 应尽可能“静态”。这意味着你不应该动态地修改它们。例如,这意味着你不应该编写高阶 Hooks:

🌐 Hooks should be as “static” as possible. This means you shouldn’t dynamically mutate them. For example, this means you shouldn’t write higher order Hooks:

function ChatInput() {
const useDataWithLogging = withLogging(useData); // 🔴 Bad: don't write higher order Hooks
const data = useDataWithLogging();
}

Hooks 应该是不可变的,不应被修改。与其动态修改一个 Hook,不如创建一个具有所需功能的静态 Hook 版本。

🌐 Hooks should be immutable and not be mutated. Instead of mutating a Hook dynamically, create a static version of the Hook with the desired functionality.

function ChatInput() {
const data = useDataWithLogging(); // ✅ Good: Create a new version of the Hook
}

function useDataWithLogging() {
// ... Create a new version of the Hook and inline the logic here
}

不要动态使用钩子

🌐 Don’t dynamically use Hooks

Hook 也不应该被动态使用:例如,不要通过将 Hook 作为值传递来在组件中进行依赖注入:

🌐 Hooks should also not be dynamically used: for example, instead of doing dependency injection in a component by passing a Hook as a value:

function ChatInput() {
return <Button useData={useDataWithLogging} /> // 🔴 Bad: don't pass Hooks as props
}

你应该始终将钩子的调用内联到该组件中并处理其中的任何逻辑。

🌐 You should always inline the call of the Hook into that component and handle any logic in there.

function ChatInput() {
return <Button />
}

function Button() {
const data = useDataWithLogging(); // ✅ Good: Use the Hook directly
}

function useDataWithLogging() {
// If there's any conditional logic to change the Hook's behavior, it should be inlined into
// the Hook
}

这样,<Button /> 更容易理解和调试。当 Hooks 以动态方式使用时,会大大增加应用的复杂性,并阻碍局部推断,长期来看会降低团队的生产力。它还会更容易意外违反 Hooks 规则,即 Hooks 不应该在条件语句中调用。如果你发现自己需要为测试模拟组件,最好模拟服务器以返回预设数据。如果可能的话,通常使用端到端测试测试你的应用也更为有效。

🌐 This way, <Button /> is much easier to understand and debug. When Hooks are used in dynamic ways, it increases the complexity of your app greatly and inhibits local reasoning, making your team less productive in the long term. It also makes it easier to accidentally break the Rules of Hooks that Hooks should not be called conditionally. If you find yourself needing to mock components for tests, it’s better to mock the server instead to respond with canned data. If possible, it’s also usually more effective to test your app with end-to-end tests.