diff --git a/public/images/docs/diagrams/conditional_render_tree.dark.png b/public/images/docs/diagrams/conditional_render_tree.dark.png new file mode 100644 index 0000000000..5189a44c80 Binary files /dev/null and b/public/images/docs/diagrams/conditional_render_tree.dark.png differ diff --git a/public/images/docs/diagrams/conditional_render_tree.png b/public/images/docs/diagrams/conditional_render_tree.png new file mode 100644 index 0000000000..c76e8cb634 Binary files /dev/null and b/public/images/docs/diagrams/conditional_render_tree.png differ diff --git a/public/images/docs/diagrams/generic_dependency_tree.dark.png b/public/images/docs/diagrams/generic_dependency_tree.dark.png new file mode 100644 index 0000000000..64694f5857 Binary files /dev/null and b/public/images/docs/diagrams/generic_dependency_tree.dark.png differ diff --git a/public/images/docs/diagrams/generic_dependency_tree.png b/public/images/docs/diagrams/generic_dependency_tree.png new file mode 100644 index 0000000000..8ab6f1a346 Binary files /dev/null and b/public/images/docs/diagrams/generic_dependency_tree.png differ diff --git a/public/images/docs/diagrams/generic_render_tree.dark.png b/public/images/docs/diagrams/generic_render_tree.dark.png new file mode 100644 index 0000000000..859fdaa96c Binary files /dev/null and b/public/images/docs/diagrams/generic_render_tree.dark.png differ diff --git a/public/images/docs/diagrams/generic_render_tree.png b/public/images/docs/diagrams/generic_render_tree.png new file mode 100644 index 0000000000..952cf5faa0 Binary files /dev/null and b/public/images/docs/diagrams/generic_render_tree.png differ diff --git a/public/images/docs/diagrams/module_dependency_tree.dark.png b/public/images/docs/diagrams/module_dependency_tree.dark.png new file mode 100644 index 0000000000..e8a85f7c0e Binary files /dev/null and b/public/images/docs/diagrams/module_dependency_tree.dark.png differ diff --git a/public/images/docs/diagrams/module_dependency_tree.png b/public/images/docs/diagrams/module_dependency_tree.png new file mode 100644 index 0000000000..0dcaaa7aa8 Binary files /dev/null and b/public/images/docs/diagrams/module_dependency_tree.png differ diff --git a/public/images/docs/diagrams/render_tree.dark.png b/public/images/docs/diagrams/render_tree.dark.png new file mode 100644 index 0000000000..117d7ff3e9 Binary files /dev/null and b/public/images/docs/diagrams/render_tree.dark.png differ diff --git a/public/images/docs/diagrams/render_tree.png b/public/images/docs/diagrams/render_tree.png new file mode 100644 index 0000000000..1ea750bb07 Binary files /dev/null and b/public/images/docs/diagrams/render_tree.png differ diff --git a/src/content/learn/describing-the-ui.md b/src/content/learn/describing-the-ui.md index b90c5cdba1..98ba57e880 100644 --- a/src/content/learn/describing-the-ui.md +++ b/src/content/learn/describing-the-ui.md @@ -15,6 +15,7 @@ React 是一个用于构建用户界面(UI)的 JavaScript 库,用户界面 +<<<<<<< HEAD * [如何创建你的第一个组件](/learn/your-first-component) * [在什么时候以及如何创建多文件组件](/learn/importing-and-exporting-components) * [如何使用 JSX 为 JavaScript 添加标签](/learn/writing-markup-with-jsx) @@ -23,6 +24,17 @@ React 是一个用于构建用户界面(UI)的 JavaScript 库,用户界面 * [如何有条件地渲染组件](/learn/conditional-rendering) * [如何在同一时间渲染多个组件](/learn/rendering-lists) * [如何通过保持组件的纯粹性来避免令人困惑的错误](/learn/keeping-components-pure) +======= +* [How to write your first React component](/learn/your-first-component) +* [When and how to create multi-component files](/learn/importing-and-exporting-components) +* [How to add markup to JavaScript with JSX](/learn/writing-markup-with-jsx) +* [How to use curly braces with JSX to access JavaScript functionality from your components](/learn/javascript-in-jsx-with-curly-braces) +* [How to configure components with props](/learn/passing-props-to-a-component) +* [How to conditionally render components](/learn/conditional-rendering) +* [How to render multiple components at a time](/learn/rendering-lists) +* [How to avoid confusing bugs by keeping components pure](/learn/keeping-components-pure) +* [Why understanding your UI as trees is useful](/learn/understanding-your-ui-as-a-tree) +>>>>>>> 9af01e2bb2c6517c3ca14b551cdfa42424370a6e @@ -526,7 +538,34 @@ export default function TeaSet() { +<<<<<<< HEAD ## 下节预告 {/*whats-next*/} +======= +## Your UI as a tree {/*your-ui-as-a-tree*/} + +React uses trees to model the relationships between components and modules. + +A React render tree is a representation of the parent and child relationship between components. + +An example React render tree. + +Components near the top of the tree, near the root component, are considered top-level components. Components with no child components are leaf components. This categorization of components is useful for understanding data flow and rendering performance. + +Modelling the relationship between JavaScript modules is another useful way to understand your app. We refer to it as a module dependency tree. + +An example module dependency tree. + +A dependency tree is often used by build tools to bundle all the relevant JavaScript code for the client to download and render. A large bundle size regresses user experience for React apps. Understanding the module dependency tree is helpful to debug such issues. + + + +Read **[Your UI as a Tree](/learn/understanding-your-ui-as-a-tree)** to learn how to create a render and module dependency trees for a React app and how they're useful mental models for improving user experience and performance. + + + + +## What's next? {/*whats-next*/} +>>>>>>> 9af01e2bb2c6517c3ca14b551cdfa42424370a6e 请访问 [你的第一个组件](/learn/your-first-component) 这个章节并开始阅读! diff --git a/src/content/learn/preserving-and-resetting-state.md b/src/content/learn/preserving-and-resetting-state.md index 90c7a13e8f..f6f9fc8dc2 100644 --- a/src/content/learn/preserving-and-resetting-state.md +++ b/src/content/learn/preserving-and-resetting-state.md @@ -14,6 +14,7 @@ translators: +<<<<<<< HEAD * React 如何“处理”组件结构 * React 何时选择保留或重置 state * 如何强制 React 重置组件的 state @@ -40,7 +41,19 @@ React 会根据组件创建了一棵 UI 树,React DOM 用它来渲染 DOM ## state 与树中的某个位置相关联 {/*state-is-tied-to-a-position-in-the-tree*/} 当你为一个组件添加 state 时,你可能会觉得 state “活”在组件内部。但实际上,state 被保存在 React 内部。根据组件在 UI 树中的位置,React 将它所持有的每个 state 与正确的组件关联起来。 +======= +* When React chooses to preserve or reset the state +* How to force React to reset component's state +* How keys and types affect whether the state is preserved + + +## State is tied to a position in the render tree {/*state-is-tied-to-a-position-in-the-tree*/} + +React builds [render trees](learn/understanding-your-ui-as-a-tree#the-render-tree) for the component structure in your UI. +>>>>>>> 9af01e2bb2c6517c3ca14b551cdfa42424370a6e + +When you give a component state, you might think the state "lives" inside the component. But the state is actually held inside React. React associates each piece of state it's holding with the correct component by where that component sits in the render tree. 下面只定义了一个 `` JSX 标签,但将它渲染在了两个不同的位置: @@ -194,7 +207,11 @@ Updating state +<<<<<<< HEAD 只有当你在相同的位置渲染相同的组件时,React 才会一直保留着组件的 state。想要验证这一点,可以将两个计数器的值递增,取消勾选 “渲染第二个计数器” 复选框,然后再次勾选它: +======= +React will keep the state around for as long as you render the same component at the same position in the tree. To see this, increment both counters, then remove the second component by unchecking "Render the second counter" checkbox, and then add it back by ticking it again: +>>>>>>> 9af01e2bb2c6517c3ca14b551cdfa42424370a6e diff --git a/src/content/learn/understanding-your-ui-as-a-tree.md b/src/content/learn/understanding-your-ui-as-a-tree.md new file mode 100644 index 0000000000..948f857901 --- /dev/null +++ b/src/content/learn/understanding-your-ui-as-a-tree.md @@ -0,0 +1,299 @@ +--- +title: Understanding your UI as a Tree +--- + + + +Your React app is taking shape with many components being nested within each other. How does React keep track of your app's component structure? + +React, and many other UI libraries, model UI as a tree. Thinking of your app as a tree is useful for understanding the relationship between components to debug future concepts like performance and state management. + + + + + +* How React "sees" component structures +* What a render tree is and what it is useful for +* What a module dependency tree is and what it is useful for + + + +## Your UI as a tree {/*your-ui-as-a-tree*/} + +Trees are a relationship model between items and UI is often represented using tree structures. For example, browsers use tree structures to model HTML ([DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction)) and CSS ([CSSOM](https://developer.mozilla.org/docs/Web/API/CSS_Object_Model)). Mobile platforms also use trees to represent their view hierarchy. + + + +React creates a UI tree from your components. In this example, the UI tree is then used to render to the DOM. + + +Like browsers and mobile platforms, React also uses tree structures to manage and model the relationship between components in a React app. These trees are useful tools to understand how data flows through a React app and how to optimize rendering and app size. + +## The Render Tree {/*the-render-tree*/} + +A major feature of components is the ability to compose components of other components. As we [nest components](/learn/your-first-component#nesting-and-organizing-components), we have the concept of parent and child components, where each parent component may itself be a child of another component. + +When we render a React app, we can model this relationship in a tree, known as the render tree. + +Here is a React app that renders inspirational quotes. + + + +```js App.js +import FancyText from './FancyText'; +import InspirationGenerator from './InspirationGenerator'; +import Copyright from './Copyright'; + +export default function App() { + return ( + <> + + + + + + ); +} + +``` + +```js FancyText.js +export default function FancyText({title, text}) { + return title + ?

{text}

+ :

{text}

+} +``` + +```js InspirationGenerator.js +import * as React from 'react'; +import quotes from './quotes'; +import FancyText from './FancyText'; + +export default function InspirationGenerator({children}) { + const [index, setIndex] = React.useState(0); + const quote = quotes[index]; + const next = () => setIndex((index + 1) % quotes.length); + + return ( + <> +

Your inspirational quote is:

+ + + {children} + + ); +} +``` + +```js Copyright.js +export default function Copyright({year}) { + return

©️ {year}

; +} +``` + +```js quotes.js +export default [ + "Don’t let yesterday take up too much of today.” — Will Rogers", + "Ambition is putting a ladder against the sky.", + "A joy that's shared is a joy made double.", + ]; +``` + +```css +.fancy { + font-family: 'Georgia'; +} +.title { + color: #007AA3; + text-decoration: underline; +} +.cursive { + font-style: italic; +} +.small { + font-size: 10px; +} +``` + +
+ + + +React creates a UI tree made of components rendered, known as a render tree. + + + +From the example app, we can construct the above render tree. + +The tree is composed of nodes, each of which represents a component. `App`, `FancyText`, `Copyright`, to name a few, are all nodes in our tree. + +The root node in a React render tree is the [root component](/learn/importing-and-exporting-components#the-root-component-file) of the app. In this case, the root component is `App` and it is the first component React renders. Each arrow in the tree points from a parent component to a child component. + + + +#### Where are the HTML tags in the render tree? {/*where-are-the-html-elements-in-the-render-tree*/} + +You'll notice in the above render tree, there is no mention of the HTML tags that each component renders. This is because the render tree is only composed of React [components](learn/your-first-component#components-ui-building-blocks). + +React, as a UI framework, is platform agnostic. On react.dev, we showcase examples that render to the web, which uses HTML markup as its UI primitives. But a React app could just as likely render to a mobile or desktop platform, which may use different UI primitives like [UIView](https://developer.apple.com/documentation/uikit/uiview) or [FrameworkElement](https://learn.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement?view=windowsdesktop-7.0). + +These platform UI primitives are not a part of React. React render trees can provide insight to our React app regardless of what platform your app renders to. + + + +A render tree represents a single render pass of a React application. With [conditional rendering](/learn/conditional-rendering), a parent component may render different children depending on the data passed. + +We can update the app to conditionally render either an inspirational quote or color. + + + +```js App.js +import FancyText from './FancyText'; +import InspirationGenerator from './InspirationGenerator'; +import Copyright from './Copyright'; + +export default function App() { + return ( + <> + + + + + + ); +} + +``` + +```js FancyText.js +export default function FancyText({title, text}) { + return title + ?

{text}

+ :

{text}

+} +``` + +```js Color.js +export default function Color({value}) { + return
+} +``` + +```js InspirationGenerator.js +import * as React from 'react'; +import inspirations from './inspirations'; +import FancyText from './FancyText'; +import Color from './Color'; + +export default function InspirationGenerator({children}) { + const [index, setIndex] = React.useState(0); + const inspiration = inspirations[index]; + const next = () => setIndex((index + 1) % inspirations.length); + + return ( + <> +

Your inspirational {inspiration.type} is:

+ {inspiration.type === 'quote' + ? + : } + + + {children} + + ); +} +``` + +```js Copyright.js +export default function Copyright({year}) { + return

©️ {year}

; +} +``` + +```js inspirations.js +export default [ + {type: 'quote', value: "Don’t let yesterday take up too much of today.” — Will Rogers"}, + {type: 'color', value: "#B73636"}, + {type: 'quote', value: "Ambition is putting a ladder against the sky."}, + {type: 'color', value: "#256266"}, + {type: 'quote', value: "A joy that's shared is a joy made double."}, + {type: 'color', value: "#F9F2B4"}, +]; +``` + +```css +.fancy { + font-family: 'Georgia'; +} +.title { + color: #007AA3; + text-decoration: underline; +} +.cursive { + font-style: italic; +} +.small { + font-size: 10px; +} +.colorbox { + height: 100px; + width: 100px; + margin: 8px; +} +``` + + + + +With conditional rendering, across different renders, the render tree may render different components. + + + +In this example, depending on what `inspiration.type` is, we may render `` or ``. The render tree may be different for each render pass. + +Although render trees may differ across render pases, these trees are generally helpful for identifying what the top-level and leaf components are in a React app. Top-level components are the components nearest to the root component and affect the rendering performance of all the components beneath them and often contain the most complexity. Leaf components are near the bottom of the tree and have no child components and are often frequently re-rendered. + +Identifying these categories of components are useful for understanding data flow and performance of your app. + +## The Module Dependency Tree {/*the-module-dependency-tree*/} + +Another relationship in a React app that can be modeled with a tree are an app's module dependencies. As we [break up our components](/learn/importing-and-exporting-components#exporting-and-importing-a-component) and logic into separate files, we create [JS modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) where we may export components, functions, or constants. + +Each node in a module dependency tree is a module and each branch represents an `import` statement in that module. + +If we take the previous Inspirations app, we can build a module dependency tree, or dependency tree for short. + + + +The module dependency tree for the Inspirations app. + + + +The root node of the tree is the root module, also known as the entrypoint file. It often is the module that contains the root component. + +Comparing to the render tree of the same app, there are similar structures but some notable differences: + +* The nodes that make-up the tree represent modules, not components. +* Non-component modules, like `inspirations.js`, are also represented in this tree. The render tree only encapsulates components. +* `Copyright.js` appears under `App.js` but in the render tree, `Copyright`, the component, appears as a child of `InspirationGenerator`. This is because `InspirationGenerator` accepts JSX as [children props](/learn/passing-props-to-a-component#passing-jsx-as-children), so it renders `Copyright` as a child component but does not import the module. + +Dependency trees are useful to determine what modules are necessary to run your React app. When building a React app for production, there is typically a build step that will bundle all the necessary JavaScript to ship to the client. The tool responsible for this is called a [bundler](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview#the_modern_tooling_ecosystem), and bundlers will use the dependency tree to determine what modules should be included. + +As your app grows, often the bundle size does too. Large bundle sizes are expensive for a client to download and run and delays the time for your UI to get drawn. Getting a sense of your app's dependency tree may help with debugging these issues. + +[comment]: <> (perhaps we should also deep dive on conditional imports) + + + +* Trees are a common way to represent the relationship between entities. They are often used to model UI. +* Render trees represent the nested relationship between React components across a single render. +* With conditional rendering, the render tree may change across different renders. With different prop values, components may render different children components. +* Render trees help identify what the top-level and leaf components are. Top-level components affect the rendering performance of all components beneath them and leaf components are often re-rendered frequently. Identifying them is useful for understanding and debugging rendering performance. +* Dependency trees represent the module dependencies in a React app. +* Dependency trees are used by build tools to bundle the necessary code to ship an app. +* Dependency trees are useful for debugging large bundle sizes that slow time to paint and expose opportunities for optimizing what code is bundled. + + + +[TODO]: <> (Add challenges) \ No newline at end of file diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 823b936b0f..80e2bb1309 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -86,6 +86,10 @@ { "title": "保持组件纯粹", "path": "/learn/keeping-components-pure" + }, + { + "title": "Your UI as a Tree", + "path": "/learn/understanding-your-ui-as-a-tree" } ] },