From 31f0e37539ad284e1a6e1f42a07d69a0f92a808b Mon Sep 17 00:00:00 2001 From: astropsy999 Date: Sun, 18 Aug 2024 20:30:19 +0300 Subject: [PATCH 001/139] finished translation scaling-up-with-reducer-and-context --- .../scaling-up-with-reducer-and-context.md | 232 +++++++++--------- src/sidebarLearn.json | 2 +- 2 files changed, 119 insertions(+), 115 deletions(-) diff --git a/src/content/learn/scaling-up-with-reducer-and-context.md b/src/content/learn/scaling-up-with-reducer-and-context.md index c3da0c637..217d0f744 100644 --- a/src/content/learn/scaling-up-with-reducer-and-context.md +++ b/src/content/learn/scaling-up-with-reducer-and-context.md @@ -1,24 +1,24 @@ --- -title: Scaling Up with Reducer and Context +title: Масштабування з використанням контексту та ред'юсера --- -Reducers let you consolidate a component's state update logic. Context lets you pass information deep down to other components. You can combine reducers and context together to manage state of a complex screen. +Ред'юсери дозволяють об'єднати логіку оновлення стану компонента. Контекст дозволяє передавати інформацію у глибину до інших компонентів. Ви можете поєднати ред'юсери і контекст, щоб управляти станом складного інтерфейсу. -* How to combine a reducer with context -* How to avoid passing state and dispatch through props -* How to keep context and state logic in a separate file +* Як поєднати ред'юсер з контекстом +* Як уникнути передачі стану та диспатча через пропси +* Як зберігати логіку контексту і стану в окремому файлі -## Combining a reducer with context {/*combining-a-reducer-with-context*/} +## Поєднання ред'юсера з контекстом {/*combining-a-reducer-with-context*/} -In this example from [the introduction to reducers](/learn/extracting-state-logic-into-a-reducer), the state is managed by a reducer. The reducer function contains all of the state update logic and is declared at the bottom of this file: + Як ми вже бачили, у прикладі з [цього розділу](/learn/extracting-state-logic-into-a-reducer), стан керується ред'юсером. Функція ред'юсера містить всю логіку оновлення стану і оголошена в кінці файлу: @@ -57,7 +57,7 @@ export default function TaskApp() { return ( <> -

Day off in Kyoto

+

Вихідний у Кіото

@@ -99,9 +99,9 @@ function tasksReducer(tasks, action) { let nextId = 3; const initialTasks = [ - { id: 0, text: 'Philosopher’s Path', done: true }, - { id: 1, text: 'Visit the temple', done: false }, - { id: 2, text: 'Drink matcha', done: false } + { id: 0, text: 'Шлях філософів', done: true }, + { id: 1, text: 'Відвідати храм', done: false }, + { id: 2, text: 'Випити матчу', done: false } ]; ``` @@ -113,14 +113,14 @@ export default function AddTask({ onAddTask }) { return ( <> setText(e.target.value)} /> + }}>Додати ) } @@ -164,7 +164,7 @@ function Task({ task, onChange, onDelete }) { }); }} /> ); @@ -173,7 +173,7 @@ function Task({ task, onChange, onDelete }) { <> {task.text} ); @@ -192,7 +192,7 @@ function Task({ task, onChange, onDelete }) { /> {taskContent} ); @@ -207,9 +207,13 @@ ul, li { margin: 0; padding: 0; }
-A reducer helps keep the event handlers short and concise. However, as your app grows, you might run into another difficulty. **Currently, the `tasks` state and the `dispatch` function are only available in the top-level `TaskApp` component.** To let other components read the list of tasks or change it, you have to explicitly [pass down](/learn/passing-props-to-a-component) the current state and the event handlers that change it as props. +Ред'юсер допомагає тримати обробники подій короткими і зрозумілими. Проте, з розвитком вашого додатка може виникнути проблема. **Наразі стан `tasks` та функція `dispatch` доступні тільки в компоненті `TaskApp` на верхньому рівні.** Щоб інші компоненти могли отримувати та оновлювати перелік завдань, потрібно явно [передавати](#passing-props-to-a-component) пропсами поточний стан і обробники подій. + +Наприклад, `TaskApp` передає перелік завдань і обробники подій компоненту `TaskList`: + +```jsx + -For example, `TaskApp` passes a list of tasks and the event handlers to `TaskList`: ```js ``` -And `TaskList` passes the event handlers to `Task`: +А `TaskList` передає обробники компоненту `Task`: ```js ``` -In a small example like this, this works well, but if you have tens or hundreds of components in the middle, passing down all state and functions can be quite frustrating! +У невеликому прикладі це добре працює, але якщо у вас є десятки або сотні вкладених компонентів, передавати таким чином весь стан і функції може бути досить неприємно! -This is why, as an alternative to passing them through props, you might want to put both the `tasks` state and the `dispatch` function [into context.](/learn/passing-data-deeply-with-context) **This way, any component below `TaskApp` in the tree can read the tasks and dispatch actions without the repetitive "prop drilling".** +Тому, як альтернатива передачі через пропси, ви можете помістити і стан `tasks`, і функцію `dispatch` [в контекст](/learn/passing-data-deeply-with-context). **Таким чином, будь-який компонент, що знаходиться нижче `TaskApp` у дереві, може мати доступ та надсилати події, уникнувши передачі пропсів через безліч компонентів.** -Here is how you can combine a reducer with context: +Ось як можна поєднати ред'юсер із контекстом: -1. **Create** the context. -2. **Put** state and dispatch into context. -3. **Use** context anywhere in the tree. +1. **Створіть** контекст. +2. **Розмістіть** стан і диспетчер у контексті. +3. **Використовуйте** контекст будь-де в дереві компонентів. -### Step 1: Create the context {/*step-1-create-the-context*/} +### Крок 1: Створення контексту {/*step-1-create-the-context*/} -The `useReducer` Hook returns the current `tasks` and the `dispatch` function that lets you update them: +Хук `useReducer` повертає поточний стан `tasks` та функцію `dispatch`, яка дозволяє оновлювати цей стан: ```js const [tasks, dispatch] = useReducer(tasksReducer, initialTasks); ``` -To pass them down the tree, you will [create](/learn/passing-data-deeply-with-context#step-2-use-the-context) two separate contexts: +Щоб передати їх далі по дереву, [створить](/learn/passing-data-deeply-with-context#step-2-use-the-context) два окремих контексти: -- `TasksContext` provides the current list of tasks. -- `TasksDispatchContext` provides the function that lets components dispatch actions. +- `TasksContext` надає поточний перелік завдань. +- `TasksDispatchContext` надає функцію, яка дозволяє компонентам надсилати події. -Export them from a separate file so that you can later import them from other files: +Експортуйте їх з окремого файлу, щоб згодом імпортувати в інших місцях: @@ -291,7 +295,7 @@ export default function TaskApp() { return ( <> -

Day off in Kyoto

+

Вихідний у Кіото

@@ -333,9 +337,9 @@ function tasksReducer(tasks, action) { let nextId = 3; const initialTasks = [ - { id: 0, text: 'Philosopher’s Path', done: true }, - { id: 1, text: 'Visit the temple', done: false }, - { id: 2, text: 'Drink matcha', done: false } + { id: 0, text: 'Шлях філософів', done: true }, + { id: 1, text: 'Відвідати Храм', done: false }, + { id: 2, text: 'Випити матчу', done: false } ]; ``` @@ -354,14 +358,14 @@ export default function AddTask({ onAddTask }) { return ( <> setText(e.target.value)} /> + }}>Додати ) } @@ -405,7 +409,7 @@ function Task({ task, onChange, onDelete }) { }); }} /> ); @@ -414,7 +418,7 @@ function Task({ task, onChange, onDelete }) { <> {task.text} ); @@ -433,7 +437,7 @@ function Task({ task, onChange, onDelete }) { /> {taskContent} ); @@ -448,11 +452,11 @@ ul, li { margin: 0; padding: 0; }
-Here, you're passing `null` as the default value to both contexts. The actual values will be provided by the `TaskApp` component. +Тут ви передаєте `null` як значення за замовчуванням для обох контекстів. Дійсні значення будуть надані компонентом `TaskApp`. -### Step 2: Put state and dispatch into context {/*step-2-put-state-and-dispatch-into-context*/} +### Крок 2: Помістіть стан і функцію dispatch у контекст {/*step-2-put-state-and-dispatch-into-context*/} -Now you can import both contexts in your `TaskApp` component. Take the `tasks` and `dispatch` returned by `useReducer()` and [provide them](/learn/passing-data-deeply-with-context#step-3-provide-the-context) to the entire tree below: +Тепер ви можете імпортувати обидва контексти у ваш компонент `TaskApp`. Візьміть `tasks` та `dispatch`, які повертає `useReducer()`, і [надайте їх](/learn/passing-data-deeply-with-context#step-3-provide-the-context) всьому вкладеному дереву компонентів: ```js {4,7-8} import { TasksContext, TasksDispatchContext } from './TasksContext.js'; @@ -470,7 +474,7 @@ export default function TaskApp() { } ``` -For now, you pass the information both via props and in context: +Наразі ви передаєте інформацію як через пропси, так і через контекст: @@ -511,7 +515,7 @@ export default function TaskApp() { return ( -

Day off in Kyoto

+

Вихідний у Кіото

@@ -554,9 +558,9 @@ function tasksReducer(tasks, action) { let nextId = 3; const initialTasks = [ - { id: 0, text: 'Philosopher’s Path', done: true }, - { id: 1, text: 'Visit the temple', done: false }, - { id: 2, text: 'Drink matcha', done: false } + { id: 0, text: 'Шлях філософів', done: true }, + { id: 1, text: 'Відвідати Храм', done: false }, + { id: 2, text: 'Випити матчу', done: false } ]; ``` @@ -575,14 +579,14 @@ export default function AddTask({ onAddTask }) { return ( <> setText(e.target.value)} /> + }}>Додати ) } @@ -626,7 +630,7 @@ function Task({ task, onChange, onDelete }) { }); }} /> ); @@ -635,7 +639,7 @@ function Task({ task, onChange, onDelete }) { <> {task.text} ); @@ -654,7 +658,7 @@ function Task({ task, onChange, onDelete }) { /> {taskContent} ); @@ -669,23 +673,23 @@ ul, li { margin: 0; padding: 0; }
-In the next step, you will remove prop passing. +На наступному етапі видалимо передачу пропсів. -### Step 3: Use context anywhere in the tree {/*step-3-use-context-anywhere-in-the-tree*/} +### Step 3: Використовуйте контекст у будь-якому місці дерева компонентів {/*step-3-use-context-anywhere-in-the-tree*/} -Now you don't need to pass the list of tasks or the event handlers down the tree: +Тепер вам не потрібно передавати перелік завдань або обробники подій скрізь усе дерево компонентів: ```js {4-5} -

Day off in Kyoto

+

Вихідний у Кіото

``` -Instead, any component that needs the task list can read it from the `TaskContext`: +Натомість будь-який компонент, якому потрібен перелік завдань, може мати його з `TaskContext`: ```js {2} export default function TaskList() { @@ -693,7 +697,7 @@ export default function TaskList() { // ... ``` -To update the task list, any component can read the `dispatch` function from context and call it: +Щоб оновити перелік завдань, будь-який компонент може взяти функцію `dispatch` з контексту та викликати її: ```js {3,9-13} export default function AddTask() { @@ -709,11 +713,11 @@ export default function AddTask() { id: nextId++, text: text, }); - }}>Add + }}>Додати // ... ``` -**The `TaskApp` component does not pass any event handlers down, and the `TaskList` does not pass any event handlers to the `Task` component either.** Each component reads the context that it needs: +**Компонент `TaskApp` не передає жодних обробників подій, і `TaskList` також не передає нічого компоненту `Task`.** Кожен компонент обирає лише потрібний йому контекст: @@ -732,7 +736,7 @@ export default function TaskApp() { return ( -

Day off in Kyoto

+

Вихідний у Кіото

@@ -768,9 +772,9 @@ function tasksReducer(tasks, action) { } const initialTasks = [ - { id: 0, text: 'Philosopher’s Path', done: true }, - { id: 1, text: 'Visit the temple', done: false }, - { id: 2, text: 'Drink matcha', done: false } + { id: 0, text: 'Шлях філософів', done: true }, + { id: 1, text: 'Відвідати Храм', done: false }, + { id: 2, text: 'Випити матчу', done: false } ]; ``` @@ -791,7 +795,7 @@ export default function AddTask() { return ( <> setText(e.target.value)} /> @@ -801,8 +805,8 @@ export default function AddTask() { type: 'added', id: nextId++, text: text, - }); - }}>Add + }); + }}>Додати ); } @@ -846,7 +850,7 @@ function Task({ task }) { }); }} /> ); @@ -855,7 +859,7 @@ function Task({ task }) { <> {task.text} ); @@ -882,7 +886,7 @@ function Task({ task }) { id: task.id }); }}> - Delete + Видалити ); @@ -897,11 +901,11 @@ ul, li { margin: 0; padding: 0; }
-**The state still "lives" in the top-level `TaskApp` component, managed with `useReducer`.** But its `tasks` and `dispatch` are now available to every component below in the tree by importing and using these contexts. +**Стан все ще "живе" у компоненті `TaskApp` на верхньому рівні та керується за допомогою `useReducer`.** Але його `tasks` і `dispatch` тепер доступні кожному компоненту нижче в дереві, завдяки імпорту та використанню контекстів. -## Moving all wiring into a single file {/*moving-all-wiring-into-a-single-file*/} +## Переміщення всієї логіки в один файл {/*moving-all-wiring-into-a-single-file*/} -You don't have to do this, but you could further declutter the components by moving both reducer and context into a single file. Currently, `TasksContext.js` contains only two context declarations: +Це не обов'язково, але ви можете ще більше спростити компоненти, перемістивши і ред'юсер, і контекст в один файл. Наразі `TasksContext.js` містить лише два оголошення контексту: ```js import { createContext } from 'react'; @@ -910,11 +914,11 @@ export const TasksContext = createContext(null); export const TasksDispatchContext = createContext(null); ``` -This file is about to get crowded! You'll move the reducer into that same file. Then you'll declare a new `TasksProvider` component in the same file. This component will tie all the pieces together: +Цей файл скоро стане більш наповненим! Додамо в нього ред'юсер. Потім оголосимо новий компонент `TasksProvider`. Цей компонент об’єднає всі частини разом. Він: -1. It will manage the state with a reducer. -2. It will provide both contexts to components below. -3. It will [take `children` as a prop](/learn/passing-props-to-a-component#passing-jsx-as-children) so you can pass JSX to it. +1. Керуватиме станом за допомогою ред'юсера. +2. Надаватиме обидва контексти компонентам нижчим в ієрархії. +3. [Прийматиме `children` як пропс](/learn/passing-props-to-a-component#passing-jsx-as-children), щоб було можливим передавати в нього JSX. ```js export function TasksProvider({ children }) { @@ -930,7 +934,7 @@ export function TasksProvider({ children }) { } ``` -**This removes all the complexity and wiring from your `TaskApp` component:** +**Це усуває всю складну логіку з компонента `TaskApp`:** @@ -942,7 +946,7 @@ import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return ( -

Day off in Kyoto

+

Вихідний у Кіото

@@ -999,9 +1003,9 @@ function tasksReducer(tasks, action) { } const initialTasks = [ - { id: 0, text: 'Philosopher’s Path', done: true }, - { id: 1, text: 'Visit the temple', done: false }, - { id: 2, text: 'Drink matcha', done: false } + { id: 0, text: 'Шлях філософів', done: true }, + { id: 1, text: 'Відвідати Храм', done: false }, + { id: 2, text: 'Випити матчу', done: false } ]; ``` @@ -1015,7 +1019,7 @@ export default function AddTask() { return ( <> setText(e.target.value)} /> @@ -1025,8 +1029,8 @@ export default function AddTask() { type: 'added', id: nextId++, text: text, - }); - }}>Add + }); + }}>Додати ); } @@ -1070,7 +1074,7 @@ function Task({ task }) { }); }} /> ); @@ -1079,7 +1083,7 @@ function Task({ task }) { <> {task.text} ); @@ -1106,7 +1110,7 @@ function Task({ task }) { id: task.id }); }}> - Delete + Видалити ); @@ -1121,7 +1125,7 @@ ul, li { margin: 0; padding: 0; }
-You can also export functions that _use_ the context from `TasksContext.js`: +Ви також можете експортувати функції, які _використовують_ контекст, із файлу `TasksContext.js`: ```js export function useTasks() { @@ -1133,14 +1137,14 @@ export function useTasksDispatch() { } ``` -When a component needs to read context, it can do it through these functions: +За допомогою цих функцій компоненти можуть взаємодіяти з контекстом. ```js const tasks = useTasks(); const dispatch = useTasksDispatch(); ``` -This doesn't change the behavior in any way, but it lets you later split these contexts further or add some logic to these functions. **Now all of the context and reducer wiring is in `TasksContext.js`. This keeps the components clean and uncluttered, focused on what they display rather than where they get the data:** +**Це не змінює функціональність, але дозволяє згодом розділити контексти або додати логіку. Тепер усі налаштування контексту та ред'юсера знаходяться у файлі `TasksContext.js`. Це допомагає зберегти компоненти чистими і не перевантаженими, зосередженими на відображенні даних, а не на їх отриманні.** @@ -1152,7 +1156,7 @@ import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return ( -

Day off in Kyoto

+

Вихідний у Кіото

@@ -1218,9 +1222,9 @@ function tasksReducer(tasks, action) { } const initialTasks = [ - { id: 0, text: 'Philosopher’s Path', done: true }, - { id: 1, text: 'Visit the temple', done: false }, - { id: 2, text: 'Drink matcha', done: false } + { id: 0, text: 'Шлях філософів', done: true }, + { id: 1, text: 'Відвідати Храм', done: false }, + { id: 2, text: 'Випити матчу', done: false } ]; ``` @@ -1234,7 +1238,7 @@ export default function AddTask() { return ( <> setText(e.target.value)} /> @@ -1244,8 +1248,8 @@ export default function AddTask() { type: 'added', id: nextId++, text: text, - }); - }}>Add + }); + }}>Додати ); } @@ -1289,7 +1293,7 @@ function Task({ task }) { }); }} /> ); @@ -1298,7 +1302,7 @@ function Task({ task }) { <> {task.text} ); @@ -1325,7 +1329,7 @@ function Task({ task }) { id: task.id }); }}> - Delete + Видалити ); @@ -1340,27 +1344,27 @@ ul, li { margin: 0; padding: 0; }
-You can think of `TasksProvider` as a part of the screen that knows how to deal with tasks, `useTasks` as a way to read them, and `useTasksDispatch` as a way to update them from any component below in the tree. +Ви можете вважати `TasksProvider` частиною інтерфейсу, яка відповідає за роботу з завданнями, `useTasks` — способом доступу до завдань, а `useTasksDispatch` — способом їх оновлення з будь-якого компонента, що знаходиться нижче в дереві компонентів. -Functions like `useTasks` and `useTasksDispatch` are called *[Custom Hooks.](/learn/reusing-logic-with-custom-hooks)* Your function is considered a custom Hook if its name starts with `use`. This lets you use other Hooks, like `useContext`, inside it. +Функції на кшталт `useTasks` та `useTasksDispatch` називаються *[Хуками користувача](/learn/reusing-logic-with-custom-hooks)*. Ваша функція вважається хуком користувача, якщо її назва починається з `use`. Це дозволяє використовувати інші хуки, як-от `useContext`, всередині неї. -As your app grows, you may have many context-reducer pairs like this. This is a powerful way to scale your app and [lift state up](/learn/sharing-state-between-components) without too much work whenever you want to access the data deep in the tree. +Коли додаток зростає, у вас може з’явитися багато пар контекст-ред'юсерів. Це потужний спосіб масштабувати додаток і [ділитися станом](/learn/sharing-state-between-components) без зайвих зусиль щоразу, коли потрібно отримати дані з глибини дерева компонентів. -- You can combine reducer with context to let any component read and update state above it. -- To provide state and the dispatch function to components below: - 1. Create two contexts (for state and for dispatch functions). - 2. Provide both contexts from the component that uses the reducer. - 3. Use either context from components that need to read them. -- You can further declutter the components by moving all wiring into one file. - - You can export a component like `TasksProvider` that provides context. - - You can also export custom Hooks like `useTasks` and `useTasksDispatch` to read it. -- You can have many context-reducer pairs like this in your app. +- Ви можете об'єднати ред'юсер з контекстом, щоб будь-який компонент міг мати доступ та оновлювати стан у компонентах вищих за ієрархією. +- Щоб надати стан і функцію `dispatch` компонентам нижче: + 1. Створіть два контексти (для стану і для функцій `dispatch`). + 2. Надайте обидва контексти компоненту, який використовує ред'юсер. + 3. Використовуйте будь-який контекст у компонентах, яким потрібно мати ці дані. +- Щоб ще більше спростити компоненти, виносьте ці налаштування в один файл. + - Експортуйте компонент, наприклад `TasksProvider`, який надає контекст. + - Ви також можете експортувати користувацькі хуки, як-от `useTasks` та `useTasksDispatch`, для доступу до контексту. +- У додатку може бути багато схожих на цю пар контекст-ред'юсерів. diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 88e87f9b9..138671c11 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -163,7 +163,7 @@ "path": "/learn/passing-data-deeply-with-context" }, { - "title": "Scaling Up with Reducer and Context", + "title": "Масштабування з використанням контексту та ред'юсера", "path": "/learn/scaling-up-with-reducer-and-context" } ] From 67e485c957b4f7ed576ae2250ffd78b5a6f03ea3 Mon Sep 17 00:00:00 2001 From: astropsy999 Date: Thu, 19 Sep 2024 21:46:48 +0300 Subject: [PATCH 002/139] Apply suggestions from code review --- .../scaling-up-with-reducer-and-context.md | 80 +++++++++---------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/src/content/learn/scaling-up-with-reducer-and-context.md b/src/content/learn/scaling-up-with-reducer-and-context.md index 217d0f744..698839ef0 100644 --- a/src/content/learn/scaling-up-with-reducer-and-context.md +++ b/src/content/learn/scaling-up-with-reducer-and-context.md @@ -1,24 +1,24 @@ --- -title: Масштабування з використанням контексту та ред'юсера +title: Масштабування з використанням контексту та редюсера --- -Ред'юсери дозволяють об'єднати логіку оновлення стану компонента. Контекст дозволяє передавати інформацію у глибину до інших компонентів. Ви можете поєднати ред'юсери і контекст, щоб управляти станом складного інтерфейсу. +Редюсери дають змогу об'єднати логіку оновлення стану компонента. Контекст дає змогу передавати інформацію у глибину до інших компонентів. Можна поєднати редюсери і контекст, щоб управляти станом складного інтерфейсу. -* Як поєднати ред'юсер з контекстом +* Як поєднати з контекстом * Як уникнути передачі стану та диспатча через пропси * Як зберігати логіку контексту і стану в окремому файлі -## Поєднання ред'юсера з контекстом {/*combining-a-reducer-with-context*/} +## Поєднання редюсера з контекстом {/*combining-a-reducer-with-context*/} - Як ми вже бачили, у прикладі з [цього розділу](/learn/extracting-state-logic-into-a-reducer), стан керується ред'юсером. Функція ред'юсера містить всю логіку оновлення стану і оголошена в кінці файлу: + Як ми вже бачили, у прикладі з [цього розділу](/learn/extracting-state-logic-into-a-reducer), стан керується редюсером. Функція редюсера містить всю логіку оновлення стану і оголошена в кінці файлу: @@ -57,7 +57,7 @@ export default function TaskApp() { return ( <> -

Вихідний у Кіото

+

Вихідний день у Кіото

@@ -99,7 +99,7 @@ function tasksReducer(tasks, action) { let nextId = 3; const initialTasks = [ - { id: 0, text: 'Шлях філософів', done: true }, + { id: 0, text: 'Шлях філософа', done: true }, { id: 1, text: 'Відвідати храм', done: false }, { id: 2, text: 'Випити матчу', done: false } ]; @@ -113,7 +113,7 @@ export default function AddTask({ onAddTask }) { return ( <> setText(e.target.value)} /> @@ -207,19 +207,15 @@ ul, li { margin: 0; padding: 0; }
-Ред'юсер допомагає тримати обробники подій короткими і зрозумілими. Проте, з розвитком вашого додатка може виникнути проблема. **Наразі стан `tasks` та функція `dispatch` доступні тільки в компоненті `TaskApp` на верхньому рівні.** Щоб інші компоненти могли отримувати та оновлювати перелік завдань, потрібно явно [передавати](#passing-props-to-a-component) пропсами поточний стан і обробники подій. +Редюсер допомагає тримати обробники подій короткими і зрозумілими. Проте, з розвитком вашого додатка може виникнути проблема. **Наразі стан `tasks` та функція `dispatch` доступні тільки в компоненті `TaskApp` на верхньому рівні.** Щоб інші компоненти могли отримувати та оновлювати перелік завдань, потрібно явно [передавати](#passing-props-to-a-component) пропсами поточний стан і обробники подій. Наприклад, `TaskApp` передає перелік завдань і обробники подій компоненту `TaskList`: ```jsx - - ```js ``` @@ -237,7 +233,7 @@ ul, li { margin: 0; padding: 0; } Тому, як альтернатива передачі через пропси, ви можете помістити і стан `tasks`, і функцію `dispatch` [в контекст](/learn/passing-data-deeply-with-context). **Таким чином, будь-який компонент, що знаходиться нижче `TaskApp` у дереві, може мати доступ та надсилати події, уникнувши передачі пропсів через безліч компонентів.** -Ось як можна поєднати ред'юсер із контекстом: +Ось як можна поєднати редюсер із контекстом: 1. **Створіть** контекст. 2. **Розмістіть** стан і диспетчер у контексті. @@ -245,7 +241,7 @@ ul, li { margin: 0; padding: 0; } ### Крок 1: Створення контексту {/*step-1-create-the-context*/} -Хук `useReducer` повертає поточний стан `tasks` та функцію `dispatch`, яка дозволяє оновлювати цей стан: +Хук `useReducer` повертає поточний стан `tasks` та функцію `dispatch`, яка дає змогу оновлювати цей стан: ```js const [tasks, dispatch] = useReducer(tasksReducer, initialTasks); @@ -254,7 +250,7 @@ const [tasks, dispatch] = useReducer(tasksReducer, initialTasks); Щоб передати їх далі по дереву, [створить](/learn/passing-data-deeply-with-context#step-2-use-the-context) два окремих контексти: - `TasksContext` надає поточний перелік завдань. -- `TasksDispatchContext` надає функцію, яка дозволяє компонентам надсилати події. +- `TasksDispatchContext` надає функцію, яка дає змогу компонентам надсилати події. Експортуйте їх з окремого файлу, щоб згодом імпортувати в інших місцях: @@ -295,7 +291,7 @@ export default function TaskApp() { return ( <> -

Вихідний у Кіото

+

Вихідний день у Кіото

@@ -337,7 +333,7 @@ function tasksReducer(tasks, action) { let nextId = 3; const initialTasks = [ - { id: 0, text: 'Шлях філософів', done: true }, + { id: 0, text: 'Шлях філософа', done: true }, { id: 1, text: 'Відвідати Храм', done: false }, { id: 2, text: 'Випити матчу', done: false } ]; @@ -358,7 +354,7 @@ export default function AddTask({ onAddTask }) { return ( <> setText(e.target.value)} /> @@ -515,7 +511,7 @@ export default function TaskApp() { return ( -

Вихідний у Кіото

+

Вихідний день у Кіото

@@ -558,7 +554,7 @@ function tasksReducer(tasks, action) { let nextId = 3; const initialTasks = [ - { id: 0, text: 'Шлях філософів', done: true }, + { id: 0, text: 'Шлях філософа', done: true }, { id: 1, text: 'Відвідати Храм', done: false }, { id: 2, text: 'Випити матчу', done: false } ]; @@ -579,7 +575,7 @@ export default function AddTask({ onAddTask }) { return ( <> setText(e.target.value)} /> @@ -682,7 +678,7 @@ ul, li { margin: 0; padding: 0; } ```js {4-5} -

Вихідний у Кіото

+

Вихідний день у Кіото

@@ -736,7 +732,7 @@ export default function TaskApp() { return ( -

Вихідний у Кіото

+

Вихідний день у Кіото

@@ -772,7 +768,7 @@ function tasksReducer(tasks, action) { } const initialTasks = [ - { id: 0, text: 'Шлях філософів', done: true }, + { id: 0, text: 'Шлях філософа', done: true }, { id: 1, text: 'Відвідати Храм', done: false }, { id: 2, text: 'Випити матчу', done: false } ]; @@ -795,7 +791,7 @@ export default function AddTask() { return ( <> setText(e.target.value)} /> @@ -905,7 +901,7 @@ ul, li { margin: 0; padding: 0; } ## Переміщення всієї логіки в один файл {/*moving-all-wiring-into-a-single-file*/} -Це не обов'язково, але ви можете ще більше спростити компоненти, перемістивши і ред'юсер, і контекст в один файл. Наразі `TasksContext.js` містить лише два оголошення контексту: +Це не обов'язково, але ви можете ще більше спростити компоненти, перемістивши і редюсер, і контекст в один файл. Наразі `TasksContext.js` містить лише два оголошення контексту: ```js import { createContext } from 'react'; @@ -914,9 +910,9 @@ export const TasksContext = createContext(null); export const TasksDispatchContext = createContext(null); ``` -Цей файл скоро стане більш наповненим! Додамо в нього ред'юсер. Потім оголосимо новий компонент `TasksProvider`. Цей компонент об’єднає всі частини разом. Він: +Цей файл скоро стане більш наповненим! Додамо в нього редюсер. Потім оголосимо новий компонент `TasksProvider`. Цей компонент об’єднає всі частини разом. Він: -1. Керуватиме станом за допомогою ред'юсера. +1. Керуватиме станом за допомогою редюсера. 2. Надаватиме обидва контексти компонентам нижчим в ієрархії. 3. [Прийматиме `children` як пропс](/learn/passing-props-to-a-component#passing-jsx-as-children), щоб було можливим передавати в нього JSX. @@ -946,7 +942,7 @@ import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return ( -

Вихідний у Кіото

+

Вихідний день у Кіото

@@ -1003,7 +999,7 @@ function tasksReducer(tasks, action) { } const initialTasks = [ - { id: 0, text: 'Шлях філософів', done: true }, + { id: 0, text: 'Шлях філософа', done: true }, { id: 1, text: 'Відвідати Храм', done: false }, { id: 2, text: 'Випити матчу', done: false } ]; @@ -1019,7 +1015,7 @@ export default function AddTask() { return ( <> setText(e.target.value)} /> @@ -1144,7 +1140,7 @@ const tasks = useTasks(); const dispatch = useTasksDispatch(); ``` -**Це не змінює функціональність, але дозволяє згодом розділити контексти або додати логіку. Тепер усі налаштування контексту та ред'юсера знаходяться у файлі `TasksContext.js`. Це допомагає зберегти компоненти чистими і не перевантаженими, зосередженими на відображенні даних, а не на їх отриманні.** +**Це не змінює функціональність, але дає змогу згодом розділити контексти або додати логіку. Тепер усі налаштування контексту та редюсера знаходяться у файлі `TasksContext.js`. Це допомагає зберегти компоненти чистими і не перевантаженими, зосередженими на відображенні даних, а не на їх отриманні.** @@ -1156,7 +1152,7 @@ import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return ( -

Вихідний у Кіото

+

Вихідний день у Кіото

@@ -1222,7 +1218,7 @@ function tasksReducer(tasks, action) { } const initialTasks = [ - { id: 0, text: 'Шлях філософів', done: true }, + { id: 0, text: 'Шлях філософа', done: true }, { id: 1, text: 'Відвідати Храм', done: false }, { id: 2, text: 'Випити матчу', done: false } ]; @@ -1238,7 +1234,7 @@ export default function AddTask() { return ( <> setText(e.target.value)} /> @@ -1348,23 +1344,23 @@ ul, li { margin: 0; padding: 0; } -Функції на кшталт `useTasks` та `useTasksDispatch` називаються *[Хуками користувача](/learn/reusing-logic-with-custom-hooks)*. Ваша функція вважається хуком користувача, якщо її назва починається з `use`. Це дозволяє використовувати інші хуки, як-от `useContext`, всередині неї. +Функції на кшталт `useTasks` та `useTasksDispatch` називаються *[Хуками користувача](/learn/reusing-logic-with-custom-hooks)*. Ваша функція вважається хуком користувача, якщо її назва починається з `use`. Це дає змогу використовувати інші хуки, як-от `useContext`, всередині неї. -Коли додаток зростає, у вас може з’явитися багато пар контекст-ред'юсерів. Це потужний спосіб масштабувати додаток і [ділитися станом](/learn/sharing-state-between-components) без зайвих зусиль щоразу, коли потрібно отримати дані з глибини дерева компонентів. +Коли додаток зростає, у вас може з’явитися багато пар контекст-редюсерів. Це потужний спосіб масштабувати додаток і [ділитися станом](/learn/sharing-state-between-components) без зайвих зусиль щоразу, коли потрібно отримати дані з глибини дерева компонентів. -- Ви можете об'єднати ред'юсер з контекстом, щоб будь-який компонент міг мати доступ та оновлювати стан у компонентах вищих за ієрархією. +- Ви можете об'єднати редюсер з контекстом, щоб будь-який компонент міг мати доступ та оновлювати стан у компонентах вищих за ієрархією. - Щоб надати стан і функцію `dispatch` компонентам нижче: 1. Створіть два контексти (для стану і для функцій `dispatch`). - 2. Надайте обидва контексти компоненту, який використовує ред'юсер. + 2. Надайте обидва контексти компоненту, який використовує редюсер. 3. Використовуйте будь-який контекст у компонентах, яким потрібно мати ці дані. - Щоб ще більше спростити компоненти, виносьте ці налаштування в один файл. - Експортуйте компонент, наприклад `TasksProvider`, який надає контекст. - Ви також можете експортувати користувацькі хуки, як-от `useTasks` та `useTasksDispatch`, для доступу до контексту. -- У додатку може бути багато схожих на цю пар контекст-ред'юсерів. +- У додатку може бути багато схожих на цю пар контекст-редюсерів. From 0d9a5f6cb88bb5d4617707053c9fd40715d6a2f1 Mon Sep 17 00:00:00 2001 From: astropsy999 Date: Sat, 21 Sep 2024 08:16:48 +0300 Subject: [PATCH 003/139] Corrected title --- src/sidebarLearn.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 138671c11..fd83ce1a0 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -163,7 +163,7 @@ "path": "/learn/passing-data-deeply-with-context" }, { - "title": "Масштабування з використанням контексту та ред'юсера", + "title": "Масштабування з використанням контексту та редюсера", "path": "/learn/scaling-up-with-reducer-and-context" } ] From a5f2d7ae2680b745449e2163d60197b34bb85298 Mon Sep 17 00:00:00 2001 From: Alina Listunova Date: Sun, 2 Feb 2025 20:47:34 +0100 Subject: [PATCH 004/139] Apply suggestions from code review --- src/content/learn/scaling-up-with-reducer-and-context.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/scaling-up-with-reducer-and-context.md b/src/content/learn/scaling-up-with-reducer-and-context.md index 698839ef0..510013293 100644 --- a/src/content/learn/scaling-up-with-reducer-and-context.md +++ b/src/content/learn/scaling-up-with-reducer-and-context.md @@ -211,11 +211,11 @@ ul, li { margin: 0; padding: 0; } Наприклад, `TaskApp` передає перелік завдань і обробники подій компоненту `TaskList`: -```jsx - ```js ``` From 9a18bcda9187dc78cf494c19e7580e356907ca21 Mon Sep 17 00:00:00 2001 From: Brion Mario Date: Tue, 11 Feb 2025 02:25:11 +0530 Subject: [PATCH 005/139] docs: add javascript colombo, sri lanka meetup (#7289) --- src/content/community/meetups.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/content/community/meetups.md b/src/content/community/meetups.md index 14097aa4d..e4362b44c 100644 --- a/src/content/community/meetups.md +++ b/src/content/community/meetups.md @@ -136,6 +136,9 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet ## Spain {/*spain*/} * [Barcelona](https://www.meetup.com/ReactJS-Barcelona/) +## Sri Lanka {/*sri-lanka*/} +* [Colombo](https://www.javascriptcolombo.com/) + ## Sweden {/*sweden*/} * [Goteborg](https://www.meetup.com/ReactJS-Goteborg/) * [Stockholm](https://www.meetup.com/Stockholm-ReactJS-Meetup/) From 7cb25e328b3f163d539ff73e7def7edc917209d9 Mon Sep 17 00:00:00 2001 From: Henrik Rinne Date: Mon, 10 Feb 2025 22:56:27 +0200 Subject: [PATCH 006/139] Adding React Helsinki meetup (#7474) * Update meetups.md Added React Helsinki to meetups. * Update meetups.md --- src/content/community/meetups.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/content/community/meetups.md b/src/content/community/meetups.md index e4362b44c..906c170de 100644 --- a/src/content/community/meetups.md +++ b/src/content/community/meetups.md @@ -57,6 +57,9 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [React Advanced London](https://guild.host/react-advanced-london) * [React Native London](https://guild.host/RNLDN) +## Finland {/*finland*/} +* [Helsinki](https://www.meetabit.com/communities/react-helsinki) + ## France {/*france*/} * [Lille](https://www.meetup.com/ReactBeerLille/) * [Paris](https://www.meetup.com/ReactJS-Paris/) From c76a1f7a3efbdfb57086d59ba18bcad1b2c33c8a Mon Sep 17 00:00:00 2001 From: Kiran Abburi Date: Tue, 11 Feb 2025 02:27:28 +0530 Subject: [PATCH 007/139] Added React Nexus 2025 to the conference list (#7463) --- src/content/community/conferences.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md index dd9dd2510..46636d4c9 100644 --- a/src/content/community/conferences.md +++ b/src/content/community/conferences.md @@ -40,6 +40,11 @@ June 13 - 17, 2025. In-person in Amsterdam, Netherlands + remote (hybrid event) [Website](https://reactsummit.com/) - [Twitter](https://x.com/reactsummit) +### React Nexus 2025 {/*react-nexus-2025*/} +July 03 - 05, 2025. In-person in Bangalore, India + +[Website](https://reactnexus.com/) - [Twitter](https://x.com/ReactNexus) - [Bluesky](https://bsky.app/profile/reactnexus.com) - [Linkedin](https://www.linkedin.com/company/react-nexus) - [YouTube](https://www.youtube.com/reactify_in) + ### React Universe Conf 2025 {/*react-universe-conf-2025*/} September 2-4, 2025. Wrocław, Poland. From dfc4448e0d0987d1643ddc5360f215e804badabb Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Thu, 13 Feb 2025 21:01:52 +0100 Subject: [PATCH 008/139] Reference docs for `captureOwnerStack` (#7427) Co-authored-by: Ricky --- src/components/MDX/CodeBlock/CodeBlock.tsx | 1 + .../reference/react-dom/client/createRoot.md | 770 ++--------------- .../reference/react-dom/client/hydrateRoot.md | 782 ++---------------- src/content/reference/react/Component.md | 24 +- .../reference/react/captureOwnerStack.md | 452 ++++++++++ src/sidebarReference.json | 8 +- 6 files changed, 606 insertions(+), 1431 deletions(-) create mode 100644 src/content/reference/react/captureOwnerStack.md diff --git a/src/components/MDX/CodeBlock/CodeBlock.tsx b/src/components/MDX/CodeBlock/CodeBlock.tsx index 1fd9a8a90..42165c57d 100644 --- a/src/components/MDX/CodeBlock/CodeBlock.tsx +++ b/src/components/MDX/CodeBlock/CodeBlock.tsx @@ -336,6 +336,7 @@ function getInlineDecorators( line.step === 3, 'bg-green-40 border-green-40 text-green-60 dark:text-green-30': line.step === 4, + // TODO: Some codeblocks use up to 6 steps. } ), }) diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index 54e7a7f1d..0a3933949 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -344,775 +344,127 @@ export default function App({counter}) { It is uncommon to call `render` multiple times. Usually, your components will [update state](/reference/react/useState) instead. -### Show a dialog for uncaught errors {/*show-a-dialog-for-uncaught-errors*/} +### Error logging in production {/*error-logging-in-production*/} -By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional `onUncaughtError` root option: +By default, React will log all errors to the console. To implement your own error reporting, you can provide the optional error handler root options `onUncaughtError`, `onCaughtError` and `onRecoverableError`: -```js [[1, 6, "onUncaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack"]] -import { createRoot } from 'react-dom/client'; - -const root = createRoot( - document.getElementById('root'), - { - onUncaughtError: (error, errorInfo) => { - console.error( - 'Uncaught error', - error, - errorInfo.componentStack - ); - } - } -); -root.render(); -``` - -The onUncaughtError option is a function called with two arguments: - -1. The error that was thrown. -2. An errorInfo object that contains the componentStack of the error. - -You can use the `onUncaughtError` root option to display error dialogs: - - - -```html public/index.html hidden - - - - My app - - - - - -
- - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); -} - -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); -} -``` - -```js src/index.js active +```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]] import { createRoot } from "react-dom/client"; -import App from "./App.js"; -import {reportUncaughtError} from "./reportError"; -import "./styles.css"; +import { reportCaughtError } from "./reportError"; const container = document.getElementById("root"); const root = createRoot(container, { - onUncaughtError: (error, errorInfo) => { - if (error.message !== 'Known error') { - reportUncaughtError({ + onCaughtError: (error, errorInfo) => { + if (error.message !== "Known error") { + reportCaughtError({ error, - componentStack: errorInfo.componentStack + componentStack: errorInfo.componentStack, }); } - } + }, }); -root.render(); -``` - -```js src/App.js -import { useState } from 'react'; - -export default function App() { - const [throwError, setThrowError] = useState(false); - - if (throwError) { - foo.bar = 'baz'; - } - - return ( -
- This error shows the error dialog: - -
- ); -} -``` - -
- - -### Displaying Error Boundary errors {/*displaying-error-boundary-errors*/} - -By default, React will log all errors caught by an Error Boundary to `console.error`. To override this behavior, you can provide the optional `onCaughtError` root option to handle errors caught by an [Error Boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary): - -```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack"]] -import { createRoot } from 'react-dom/client'; - -const root = createRoot( - document.getElementById('root'), - { - onCaughtError: (error, errorInfo) => { - console.error( - 'Caught error', - error, - errorInfo.componentStack - ); - } - } -); -root.render(); ``` The onCaughtError option is a function called with two arguments: -1. The error that was caught by the boundary. +1. The error that was thrown. 2. An errorInfo object that contains the componentStack of the error. -You can use the `onCaughtError` root option to display error dialogs or filter known errors from logging: +Together with `onUncaughtError` and `onRecoverableError`, you can can implement your own error reporting system: -```html public/index.html hidden - - - - My app - - - - - -
- - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; +```js src/reportError.js +function reportError({ type, error, errorInfo }) { + // The specific implementation is up to you. + // `console.error()` is only used for demonstration purposes. + console.error(type, error, "Component Stack: "); + console.error("Component Stack: ", errorInfo.componentStack); } -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); +export function onCaughtErrorProd(error, errorInfo) { + if (error.message !== "Known error") { + reportError({ type: "Caught", error, errorInfo }); } - - // Show the dialog - errorDialog.classList.remove("hidden"); } -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); +export function onUncaughtErrorProd(error, errorInfo) { + reportError({ type: "Uncaught", error, errorInfo }); } -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +export function onRecoverableErrorProd(error, errorInfo) { + reportError({ type: "Recoverable", error, errorInfo }); } ``` ```js src/index.js active import { createRoot } from "react-dom/client"; import App from "./App.js"; -import {reportCaughtError} from "./reportError"; -import "./styles.css"; +import { + onCaughtErrorProd, + onRecoverableErrorProd, + onUncaughtErrorProd, +} from "./reportError"; const container = document.getElementById("root"); const root = createRoot(container, { - onCaughtError: (error, errorInfo) => { - if (error.message !== 'Known error') { - reportCaughtError({ - error, - componentStack: errorInfo.componentStack, - }); - } - } + // Keep in mind to remove these options in development to leverage + // React's default handlers or implement your own overlay for development. + // The handlers are only specfied unconditionally here for demonstration purposes. + onCaughtError: onCaughtErrorProd, + onRecoverableError: onRecoverableErrorProd, + onUncaughtError: onUncaughtErrorProd, }); root.render(); ``` ```js src/App.js -import { useState } from 'react'; -import { ErrorBoundary } from "react-error-boundary"; - -export default function App() { - const [error, setError] = useState(null); - - function handleUnknown() { - setError("unknown"); - } +import { Component, useState } from "react"; - function handleKnown() { - setError("known"); - } - - return ( - <> - { - setError(null); - }} - > - {error != null && } - This error will not show the error dialog: - - This error will show the error dialog: - - - - - ); +function Boom() { + foo.bar = "baz"; } -function fallbackRender({ resetErrorBoundary }) { - return ( -
-

Error Boundary

-

Something went wrong.

- -
- ); -} +class ErrorBoundary extends Component { + state = { hasError: false }; -function Throw({error}) { - if (error === "known") { - throw new Error('Known error') - } else { - foo.bar = 'baz'; + static getDerivedStateFromError(error) { + return { hasError: true }; } -} -``` - -```json package.json hidden -{ - "dependencies": { - "react": "19.0.0-rc-3edc000d-20240926", - "react-dom": "19.0.0-rc-3edc000d-20240926", - "react-scripts": "^5.0.0", - "react-error-boundary": "4.0.3" - }, - "main": "/index.js" -} -``` - -
- -### Displaying a dialog for recoverable errors {/*displaying-a-dialog-for-recoverable-errors*/} - -React may automatically render a component a second time to attempt to recover from an error thrown in render. If successful, React will log a recoverable error to the console to notify the developer. To override this behavior, you can provide the optional `onRecoverableError` root option: - -```js [[1, 6, "onRecoverableError"], [2, 6, "error", 1], [3, 10, "error.cause"], [4, 6, "errorInfo"], [5, 11, "componentStack"]] -import { createRoot } from 'react-dom/client'; -const root = createRoot( - document.getElementById('root'), - { - onRecoverableError: (error, errorInfo) => { - console.error( - 'Recoverable error', - error, - error.cause, - errorInfo.componentStack, - ); + render() { + if (this.state.hasError) { + return

Something went wrong.

; } + return this.props.children; } -); -root.render(); -``` - -The onRecoverableError option is a function called with two arguments: - -1. The error that React throws. Some errors may include the original cause as error.cause. -2. An errorInfo object that contains the componentStack of the error. - -You can use the `onRecoverableError` root option to display error dialogs: - - - -```html public/index.html hidden - - - - My app - - - - - -
- - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); -} - -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); } -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); -} -``` - -```js src/index.js active -import { createRoot } from "react-dom/client"; -import App from "./App.js"; -import {reportRecoverableError} from "./reportError"; -import "./styles.css"; - -const container = document.getElementById("root"); -const root = createRoot(container, { - onRecoverableError: (error, errorInfo) => { - reportRecoverableError({ - error, - cause: error.cause, - componentStack: errorInfo.componentStack, - }); - } -}); -root.render(); -``` - -```js src/App.js -import { useState } from 'react'; -import { ErrorBoundary } from "react-error-boundary"; - -// 🚩 Bug: Never do this. This will force an error. -let errorThrown = false; export default function App() { + const [triggerUncaughtError, settriggerUncaughtError] = useState(false); + const [triggerCaughtError, setTriggerCaughtError] = useState(false); + return ( <> - - {!errorThrown && } -

This component threw an error, but recovered during a second render.

-

Since it recovered, no Error Boundary was shown, but onRecoverableError was used to show an error dialog.

-
- + + {triggerUncaughtError && } + + {triggerCaughtError && ( + + + + )} ); } - -function fallbackRender() { - return ( -
-

Error Boundary

-

Something went wrong.

-
- ); -} - -function Throw({error}) { - // Simulate an external value changing during concurrent render. - errorThrown = true; - foo.bar = 'baz'; -} -``` - -```json package.json hidden -{ - "dependencies": { - "react": "19.0.0-rc-3edc000d-20240926", - "react-dom": "19.0.0-rc-3edc000d-20240926", - "react-scripts": "^5.0.0", - "react-error-boundary": "4.0.3" - }, - "main": "/index.js" -} ```
- ---- ## Troubleshooting {/*troubleshooting*/} ### I've created a root, but nothing is displayed {/*ive-created-a-root-but-nothing-is-displayed*/} diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index b1eeca30c..887cab7d2 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -374,554 +374,124 @@ export default function App({counter}) { It is uncommon to call [`root.render`](#root-render) on a hydrated root. Usually, you'll [update state](/reference/react/useState) inside one of the components instead. -### Show a dialog for uncaught errors {/*show-a-dialog-for-uncaught-errors*/} +### Error logging in production {/*error-logging-in-production*/} -By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional `onUncaughtError` root option: +By default, React will log all errors to the console. To implement your own error reporting, you can provide the optional error handler root options `onUncaughtError`, `onCaughtError` and `onRecoverableError`: -```js [[1, 7, "onUncaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]] -import { hydrateRoot } from 'react-dom/client'; +```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]] +import { hydrateRoot } from "react-dom/client"; +import { reportCaughtError } from "./reportError"; -const root = hydrateRoot( - document.getElementById('root'), - , - { - onUncaughtError: (error, errorInfo) => { - console.error( - 'Uncaught error', +const container = document.getElementById("root"); +const root = hydrateRoot(container, { + onCaughtError: (error, errorInfo) => { + if (error.message !== "Known error") { + reportCaughtError({ error, - errorInfo.componentStack - ); + componentStack: errorInfo.componentStack, + }); } - } -); -root.render(); + }, +}); ``` -The onUncaughtError option is a function called with two arguments: +The onCaughtError option is a function called with two arguments: 1. The error that was thrown. 2. An errorInfo object that contains the componentStack of the error. -You can use the `onUncaughtError` root option to display error dialogs: +Together with `onUncaughtError` and `onRecoverableError`, you can can implement your own error reporting system: -```html public/index.html hidden - - - - My app - - - - - -
This error shows the error dialog:
- - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; +```js src/reportError.js +function reportError({ type, error, errorInfo }) { + // The specific implementation is up to you. + // `console.error()` is only used for demonstration purposes. + console.error(type, error, "Component Stack: "); + console.error("Component Stack: ", errorInfo.componentStack); } -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; +export function onCaughtErrorProd(error, errorInfo) { + if (error.message !== "Known error") { + reportError({ type: "Caught", error, errorInfo }); } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); } -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); +export function onUncaughtErrorProd(error, errorInfo) { + reportError({ type: "Uncaught", error, errorInfo }); } -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +export function onRecoverableErrorProd(error, errorInfo) { + reportError({ type: "Recoverable", error, errorInfo }); } ``` ```js src/index.js active import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; -import {reportUncaughtError} from "./reportError"; -import "./styles.css"; -import {renderToString} from 'react-dom/server'; +import { + onCaughtErrorProd, + onRecoverableErrorProd, + onUncaughtErrorProd, +} from "./reportError"; const container = document.getElementById("root"); -const root = hydrateRoot(container, , { - onUncaughtError: (error, errorInfo) => { - if (error.message !== 'Known error') { - reportUncaughtError({ - error, - componentStack: errorInfo.componentStack - }); - } - } +hydrateRoot(container, , { + // Keep in mind to remove these options in development to leverage + // React's default handlers or implement your own overlay for development. + // The handlers are only specfied unconditionally here for demonstration purposes. + onCaughtError: onCaughtErrorProd, + onRecoverableError: onRecoverableErrorProd, + onUncaughtError: onUncaughtErrorProd, }); ``` ```js src/App.js -import { useState } from 'react'; +import { Component, useState } from "react"; -export default function App() { - const [throwError, setThrowError] = useState(false); - - if (throwError) { - foo.bar = 'baz'; - } - - return ( -
- This error shows the error dialog: - -
- ); +function Boom() { + foo.bar = "baz"; } -``` -
- - -### Displaying Error Boundary errors {/*displaying-error-boundary-errors*/} - -By default, React will log all errors caught by an Error Boundary to `console.error`. To override this behavior, you can provide the optional `onCaughtError` root option for errors caught by an [Error Boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary): +class ErrorBoundary extends Component { + state = { hasError: false }; -```js [[1, 7, "onCaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]] -import { hydrateRoot } from 'react-dom/client'; - -const root = hydrateRoot( - document.getElementById('root'), - , - { - onCaughtError: (error, errorInfo) => { - console.error( - 'Caught error', - error, - errorInfo.componentStack - ); - } + static getDerivedStateFromError(error) { + return { hasError: true }; } -); -root.render(); -``` - -The onCaughtError option is a function called with two arguments: -1. The error that was caught by the boundary. -2. An errorInfo object that contains the componentStack of the error. - -You can use the `onCaughtError` root option to display error dialogs or filter known errors from logging: - - - -```html public/index.html hidden - - - - My app - - - - - -
This error will not show the error dialog:This error will show the error dialog:
- - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); -} - -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); -} -``` - -```js src/index.js active -import { hydrateRoot } from "react-dom/client"; -import App from "./App.js"; -import {reportCaughtError} from "./reportError"; -import "./styles.css"; - -const container = document.getElementById("root"); -const root = hydrateRoot(container, , { - onCaughtError: (error, errorInfo) => { - if (error.message !== 'Known error') { - reportCaughtError({ - error, - componentStack: errorInfo.componentStack - }); + render() { + if (this.state.hasError) { + return

Something went wrong.

; } + return this.props.children; } -}); -``` - -```js src/App.js -import { useState } from 'react'; -import { ErrorBoundary } from "react-error-boundary"; +} export default function App() { - const [error, setError] = useState(null); - - function handleUnknown() { - setError("unknown"); - } + const [triggerUncaughtError, settriggerUncaughtError] = useState(false); + const [triggerCaughtError, setTriggerCaughtError] = useState(false); - function handleKnown() { - setError("known"); - } - return ( <> - { - setError(null); - }} - > - {error != null && } - This error will not show the error dialog: - - This error will show the error dialog: - - - + + {triggerUncaughtError && } + + {triggerCaughtError && ( + + + + )} ); } - -function fallbackRender({ resetErrorBoundary }) { - return ( -
-

Error Boundary

-

Something went wrong.

- -
- ); -} - -function Throw({error}) { - if (error === "known") { - throw new Error('Known error') - } else { - foo.bar = 'baz'; - } -} -``` - -```json package.json hidden -{ - "dependencies": { - "react": "19.0.0-rc-3edc000d-20240926", - "react-dom": "19.0.0-rc-3edc000d-20240926", - "react-scripts": "^5.0.0", - "react-error-boundary": "4.0.3" - }, - "main": "/index.js" -} -``` - -
- -### Show a dialog for recoverable hydration mismatch errors {/*show-a-dialog-for-recoverable-hydration-mismatch-errors*/} - -When React encounters a hydration mismatch, it will automatically attempt to recover by rendering on the client. By default, React will log hydration mismatch errors to `console.error`. To override this behavior, you can provide the optional `onRecoverableError` root option: - -```js [[1, 7, "onRecoverableError"], [2, 7, "error", 1], [3, 11, "error.cause", 1], [4, 7, "errorInfo"], [5, 12, "componentStack"]] -import { hydrateRoot } from 'react-dom/client'; - -const root = hydrateRoot( - document.getElementById('root'), - , - { - onRecoverableError: (error, errorInfo) => { - console.error( - 'Caught error', - error, - error.cause, - errorInfo.componentStack - ); - } - } -); ``` -The onRecoverableError option is a function called with two arguments: - -1. The error React throws. Some errors may include the original cause as error.cause. -2. An errorInfo object that contains the componentStack of the error. - -You can use the `onRecoverableError` root option to display error dialogs for hydration mismatches: - - - ```html public/index.html hidden @@ -930,226 +500,12 @@ You can use the `onRecoverableError` root option to display error dialogs for hy - - -
Server
+
Server content before hydration.
``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); -} - -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); -} -``` - -```js src/index.js active -import { hydrateRoot } from "react-dom/client"; -import App from "./App.js"; -import {reportRecoverableError} from "./reportError"; -import "./styles.css"; - -const container = document.getElementById("root"); -const root = hydrateRoot(container, , { - onRecoverableError: (error, errorInfo) => { - reportRecoverableError({ - error, - cause: error.cause, - componentStack: errorInfo.componentStack - }); - } -}); -``` - -```js src/App.js -import { useState } from 'react'; -import { ErrorBoundary } from "react-error-boundary"; - -export default function App() { - const [error, setError] = useState(null); - - function handleUnknown() { - setError("unknown"); - } - - function handleKnown() { - setError("known"); - } - - return ( - {typeof window !== 'undefined' ? 'Client' : 'Server'} - ); -} - -function fallbackRender({ resetErrorBoundary }) { - return ( -
-

Error Boundary

-

Something went wrong.

- -
- ); -} - -function Throw({error}) { - if (error === "known") { - throw new Error('Known error') - } else { - foo.bar = 'baz'; - } -} -``` - -```json package.json hidden -{ - "dependencies": { - "react": "19.0.0-rc-3edc000d-20240926", - "react-dom": "19.0.0-rc-3edc000d-20240926", - "react-scripts": "^5.0.0", - "react-error-boundary": "4.0.3" - }, - "main": "/index.js" -} -``` -
## Troubleshooting {/*troubleshooting*/} diff --git a/src/content/reference/react/Component.md b/src/content/reference/react/Component.md index 99fa17986..0821d1593 100644 --- a/src/content/reference/react/Component.md +++ b/src/content/reference/react/Component.md @@ -1273,7 +1273,11 @@ By default, if your application throws an error during rendering, React will rem To implement an error boundary component, you need to provide [`static getDerivedStateFromError`](#static-getderivedstatefromerror) which lets you update state in response to an error and display an error message to the user. You can also optionally implement [`componentDidCatch`](#componentdidcatch) to add some extra logic, for example, to log the error to an analytics service. -```js {7-10,12-19} + With [`captureOwnerStack`](/reference/react/captureOwnerStack) you can include the Owner Stack during development. + +```js {9-12,14-27} +import * as React from 'react'; + class ErrorBoundary extends React.Component { constructor(props) { super(props); @@ -1286,12 +1290,18 @@ class ErrorBoundary extends React.Component { } componentDidCatch(error, info) { - // Example "componentStack": - // in ComponentThatThrows (created by App) - // in ErrorBoundary (created by App) - // in div (created by App) - // in App - logErrorToMyService(error, info.componentStack); + logErrorToMyService( + error, + // Example "componentStack": + // in ComponentThatThrows (created by App) + // in ErrorBoundary (created by App) + // in div (created by App) + // in App + info.componentStack, + // Only available in react@canary. + // Warning: Owner Stack is not available in production. + React.captureOwnerStack(), + ); } render() { diff --git a/src/content/reference/react/captureOwnerStack.md b/src/content/reference/react/captureOwnerStack.md new file mode 100644 index 000000000..f8ed21a8c --- /dev/null +++ b/src/content/reference/react/captureOwnerStack.md @@ -0,0 +1,452 @@ +--- +title: captureOwnerStack +--- + + + +The `captureOwnerStack` API is currently only available in React's Canary and experimental channels. Learn more about [React's release channels here](/community/versioning-policy#all-release-channels). + + + + + +`captureOwnerStack` reads the current Owner Stack in development and returns it as a string if available. + +```js +const stack = captureOwnerStack(); +``` + + + + + +--- + +## Reference {/*reference*/} + +### `captureOwnerStack()` {/*captureownerstack*/} + +Call `captureOwnerStack` to get the current Owner Stack. + +```js {5,5} +import * as React from 'react'; + +function Component() { + if (process.env.NODE_ENV !== 'production') { + const ownerStack = React.captureOwnerStack(); + console.log(ownerStack); + } +} +``` + +#### Parameters {/*parameters*/} + +`captureOwnerStack` does not take any parameters. + +#### Returns {/*returns*/} + +`captureOwnerStack` returns `string | null`. + +Owner Stacks are available in +- Component render +- Effects (e.g. `useEffect`) +- React's event handlers (e.g. ` + + +
+ + + +``` + +```js src/errorOverlay.js + +export function onConsoleError({ consoleMessage, ownerStack }) { + const errorDialog = document.getElementById("error-dialog"); + const errorBody = document.getElementById("error-body"); + const errorOwnerStack = document.getElementById("error-owner-stack"); + + // Display console.error() message + errorBody.innerText = consoleMessage; + + // Display owner stack + errorOwnerStack.innerText = ownerStack; + + // Show the dialog + errorDialog.classList.remove("hidden"); +} +``` + +```js src/index.js active +import { captureOwnerStack } from "react"; +import { createRoot } from "react-dom/client"; +import App from './App'; +import { onConsoleError } from "./errorOverlay"; +import './styles.css'; + +const originalConsoleError = console.error; +console.error = function patchedConsoleError(...args) { + originalConsoleError.apply(console, args); + const ownerStack = captureOwnerStack(); + onConsoleError({ + // Keep in mind that in a real application, console.error can be + // called with multiple arguments which you should account for. + consoleMessage: args[0], + ownerStack, + }); +}; + +const container = document.getElementById("root"); +createRoot(container).render(); +``` + +```json package.json hidden +{ + "dependencies": { + "react": "canary", + "react-dom": "canary", + "react-scripts": "latest" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + } +} +``` + +```js src/App.js +function Component() { + return ; +} + +export default function App() { + return ; +} +``` + +
+ +## Troubleshooting {/*troubleshooting*/} + +### The Owner Stack is `null` {/*the-owner-stack-is-null*/} + +The call of `captureOwnerStack` happened outside of a React controlled function e.g. in a `setTimeout` callback, after a `fetch` call or in a custom DOM event handler. During render, Effects, React event handlers, and React error handlers (e.g. `hydrateRoot#options.onCaughtError`) Owner Stacks should be available. + +In the example below, clicking the button will log an empty Owner Stack because `captureOwnerStack` was called during a custom DOM event handler. The Owner Stack must be captured earlier e.g. by moving the call of `captureOwnerStack` into the Effect body. + + +```js +import {captureOwnerStack, useEffect} from 'react'; + +export default function App() { + useEffect(() => { + // Should call `captureOwnerStack` here. + function handleEvent() { + // Calling it in a custom DOM event handler is too late. + // The Owner Stack will be `null` at this point. + console.log('Owner Stack: ', captureOwnerStack()); + } + + document.addEventListener('click', handleEvent); + + return () => { + document.removeEventListener('click', handleEvent); + } + }) + + return ; +} +``` + +```json package.json hidden +{ + "dependencies": { + "react": "canary", + "react-dom": "canary", + "react-scripts": "latest" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + } +} +``` + + + +### `captureOwnerStack` is not available {/*captureownerstack-is-not-available*/} + +`captureOwnerStack` is only exported in development builds. It will be `undefined` in production builds. If `captureOwnerStack` is used in files that are bundled for production and development, you should conditionally access it from a namespace import. + +```js +// Don't use named imports of `captureOwnerStack` in files that are bundled for development and production. +import {captureOwnerStack} from 'react'; +// Use a namespace import instead and access `captureOwnerStack` conditionally. +import * as React from 'react'; + +if (process.env.NODE_ENV !== 'production') { + const ownerStack = React.captureOwnerStack(); + console.log('Owner Stack', ownerStack); +} +``` diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 00917ad56..a044c9f5b 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -147,6 +147,11 @@ "title": "experimental_taintUniqueValue", "path": "/reference/react/experimental_taintUniqueValue", "version": "canary" + }, + { + "title": "captureOwnerStack", + "path": "/reference/react/captureOwnerStack", + "version": "canary" } ] }, @@ -304,7 +309,6 @@ "title": "prerenderToNodeStream", "path": "/reference/react-dom/static/prerenderToNodeStream" } - ] }, { @@ -398,4 +402,4 @@ ] } ] -} \ No newline at end of file +} From 7cf1f500d86d5ce0a75c3a840f808573e462b9ce Mon Sep 17 00:00:00 2001 From: Ricky Date: Fri, 14 Feb 2025 13:40:33 -0500 Subject: [PATCH 009/139] Blog and docs: Sunsetting Create React App (#7495) * Blog and docs: Sunsetting Create React App * fix link * tweaks * fix markdown * clarity + thanks --- next-env.d.ts | 3 +- .../2025/02/14/sunsetting-create-react-app.md | 309 ++++++++++++++++++ src/content/blog/index.md | 10 +- .../learn/building-a-react-framework.md | 127 +++++++ src/content/learn/creating-a-react-app.md | 116 +++++++ src/content/learn/installation.md | 29 +- src/content/learn/setup.md | 32 ++ .../learn/start-a-new-react-project.md | 130 -------- src/sidebarLearn.json | 16 +- tsconfig.json | 10 +- vercel.json | 10 + 11 files changed, 641 insertions(+), 151 deletions(-) create mode 100644 src/content/blog/2025/02/14/sunsetting-create-react-app.md create mode 100644 src/content/learn/building-a-react-framework.md create mode 100644 src/content/learn/creating-a-react-app.md create mode 100644 src/content/learn/setup.md delete mode 100644 src/content/learn/start-a-new-react-project.md diff --git a/next-env.d.ts b/next-env.d.ts index 52e831b43..3cd7048ed 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/src/content/blog/2025/02/14/sunsetting-create-react-app.md b/src/content/blog/2025/02/14/sunsetting-create-react-app.md new file mode 100644 index 000000000..22dd491e3 --- /dev/null +++ b/src/content/blog/2025/02/14/sunsetting-create-react-app.md @@ -0,0 +1,309 @@ +--- +title: "Sunsetting Create React App" +author: Matt Carroll and Ricky Hanlon +date: 2025/02/14 +description: Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework. We’re also providing docs for when a framework isn’t a good fit for your project, or you prefer to start by building a framework. +--- + +February 14, 2025 by [Matt Carroll](https://twitter.com/mattcarrollcode) and [Ricky Hanlon](https://bsky.app/profile/ricky.fm) + +--- + + + +Today, we’re deprecating [Create React App](https://create-react-app.dev/) for new apps, and encouraging existing apps to migrate to a [framework](/learn/creating-a-react-app). We’re also providing docs for when a framework isn’t a good fit for your project, or you prefer to start by [building a framework](/learn/building-a-react-framework). + + + +----- + +When we released Create React App in 2016, there was no clear way to build a new React app. + +To create a React app, you had to install a bunch of tools and wire them up together yourself to support basic features like JSX, linting, and hot reloading. This was very tricky to do correctly, so the [community](https://github.com/react-boilerplate/react-boilerplate) [created](https://github.com/kriasoft/react-starter-kit) [boilerplates](https://github.com/petehunt/react-boilerplate) for [common](https://github.com/gaearon/react-hot-boilerplate) [setups](https://github.com/erikras/react-redux-universal-hot-example). However, boilerplates were difficult to update and fragmentation made it difficult for React to release new features. + +Create React App solved these problems by combining several tools into a single recommended configuration. This allowed apps a simple way to upgrade to new tooling features, and allowed the React team to deploy non-trivial tooling changes (Fast Refresh support, React Hooks lint rules) to the broadest possible audience. + +This model became so popular that there's an entire category of tools working this way today. + +## Deprecating Create React App {/*deprecating-create-react-app*/} + +Although Create React App makes it easy to get started, [there are several limitations](#limitations-of-create-react-app) that make it difficult to build high performant production apps. In principle, we could solve these problems by essentially evolving it into a [framework](#why-we-recommend-frameworks). + +However, since Create React App currently has no active maintainers, and there are many existing frameworks that solve these problems already, we’ve decided to deprecate Create React App. + +Starting today, if you install a new app, you will see a deprecation warning: + + + + +create-react-app is deprecated. +{'\n\n'} +You can find a list of up-to-date React frameworks on react.dev +For more info see: react.dev/link/cra +{'\n\n'} +This error message will only be shown once per install. + + + + +We recommend [creating new React apps](/learn/creating-a-react-app) with a framework. All the frameworks we recommend support client-only SPAs, and can be deployed to a CDN or static hosting service without a server. + +For existing apps, these guides will help you migrate to a client-only SPA: + +* [Next.js’ Create React App migration guide](https://nextjs.org/docs/app/building-your-application/upgrading/from-create-react-app) +* [React Router’s framework adoption guide](https://reactrouter.com/upgrading/component-routes). +* [Expo Webpack to Expo Router migration guide](https://docs.expo.dev/router/migrate/from-expo-webpack/) + +Create React App will continue working in maintenance mode, and we've published a new version of Create React App to work with React 19. + +If your app has unusual constraints, or you prefer to solve these problems by building your own framework, or you just want to learn how react works from scratch, you can roll your own custom setup with React using Vite or Parcel. + +To help users get started with Vite or Parcel, we've published new docs for [Building a Framework](/learn/building-a-react-framework). Continue reading to learn more about the [limitations of Create React App](#limitations-of-create-react-app) and [why we recommend frameworks](#why-we-recommend-frameworks). + + + +#### Do you recommend Vite? {/*do-you-recommend-vite*/} + +We provide several Vite-based recommendations. + +React Router v7 is a Vite based framework which allows you to use Vite's fast development server and build tooling with a framework that provides routing and data fetching. Just like the other frameworks we recommend, you can build a SPA with React Router v7. + +We also recommend using Vite when [adding React to an existing project](/learn/add-react-to-an-existing-project), or [building a framework](/learn/building-a-react-framework). + +Just like Svelte has Sveltekit, Vue has Nuxt, and Solid has SolidStart, React recommends using a framework that integrates with build tools like Vite for new projects. + + + +## Limitations of Create React App {/*limitations-of-create-react-app*/} + +Create React App and build tools like it make it easy to get started building a React app. After running `npx create-react-app my-app`, you get a fully configured React app with a development server, linting, and a production build. + +For example, if you're building an internal admin tool, you can start with a landing page: + +```js +export default function App() { + return ( +
+

Welcome to the Admin Tool!

+
+ ) +} +``` + +This allows you to immediately start coding in React with features like JSX, default linting rules, and a bundler to run in both development and production. However, this setup is missing the tools you need to build a real production app. + +Most production apps need solutions to problems like routing, data fetching, and code splitting. + +### Routing {/*routing*/} + +Create React App does not include a specific routing solution. If you're just getting started, one option is to use `useState` to switch between routes. But doing this means that you can't share links to your app - every link would go to the same page - and structuring your app becomes difficult over time: + +```js +import {useState} from 'react'; + +import Home from './Home'; +import Dashboard from './Dashboard'; + +export default function App() { + // ❌ Routing in state does not create URLs + const [route, setRoute] = useState('home'); + return ( +
+ {route === 'home' && } + {route === 'dashboard' && } +
+ ) +} +``` + +This is why most apps that use Create React App solve add routing with a routing library like [React Router](https://reactrouter.com/) or [Tanstack Router](https://tanstack.com/router/latest). With a routing library, you can add additional routes to the app, which provides opinions on the structure of your app, and allows you to start sharing links to routes. For example, with React Router you can define routes: + +```js +import {RouterProvider, createBrowserRouter} from 'react-router'; + +import Home from './Home'; +import Dashboard from './Dashboard'; + +// ✅ Each route has it's own URL +const router = createBrowserRouter([ + {path: '/', element: }, + {path: '/dashboard', element: } +]); + +export default function App() { + return ( + + ) +} +``` + +With this change, you can share a link to `/dashboard` and the app will navigate to the dashboard page . Once you have a routing library, you can add additional features like nested routes, route guards, and route transitions, which are difficult to implement without a routing library. + +There's a tradeoff being made here: the routing library adds complexity to the app, but it also adds features that are difficult to implement without it. + +### Data Fetching {/*data-fetching*/} + +Another common problem in Create React App is data fetching. Create React App does not include a specific data fetching solution. If you're just getting started, a common option is to use `fetch` in an effect to load data. + +But doing this means that the data is fetched after the component renders, which can cause network waterfalls. Network waterfalls are caused by fetching data when your app renders instead of in parallel while the code is downloading: + +```js +export default function Dashboard() { + const [data, setData] = useState(null); + + // ❌ Fetching data in a component causes network waterfalls + useEffect(() => { + fetch('/api/data') + .then(response => response.json()) + .then(data => setData(data)); + }, []); + + return ( +
+ {data.map(item =>
{item.name}
)} +
+ ) +} +``` + +Fetching in an effect means the user has to wait longer to see the content, even though the data could have been fetched earlier. To solve this, you can use a data fetching library like [React Query](https://react-query.tanstack.com/), [SWR](https://swr.vercel.app/), [Apollo](https://www.apollographql.com/docs/react), or [Relay](https://relay.dev/) which provide options to prefetch data so the request is started before the component renders. + +These libraries work best when integrated with your routing "loader" pattern to specify data dependencies at the route level, which allows the router to optimize your data fetches: + +```js +export async function loader() { + const response = await fetch(`/api/data`); + const data = await response.json(); + return data; +} + +// ✅ Fetching data in parallel while the code is downloading +export default function Dashboard({loaderData}) { + return ( +
+ {loaderData.map(item =>
{item.name}
)} +
+ ) +} +``` + +On initial load, the router can fetch the data immediately before the route is rendered. As the user navigates around the app, the router is able to fetch both the data and the route at the same time, parallelizing the fetches. This reduces the time it takes to see the content on the screen, and can improve the user experience. + +However, this requires correctly configuring the loaders in your app and trades off complexity for performance. + +### Code Splitting {/*code-splitting*/} + +Another common problem in Create React App is [code splitting](https://www.patterns.dev/vanilla/bundle-splitting). Create React App does not include a specific code splitting solution. If you're just getting started, you might not consider code splitting at all. + +This means your app is shipped as a single bundle: + +```txt +- bundle.js 75kb +``` + +But for ideal performance, you should "split" your code into separate bundles so the user only needs to download what they need. This decreases the time the user needs to wait to load your app, by only downloading the code they need to see the page they are on. + +```txt +- core.js 25kb +- home.js 25kb +- dashboard.js 25kb +``` + +One way to do code-splitting is with `React.lazy`. However, this means that the code is not fetched until the component renders, which can cause network waterfalls. A more optimal solution is to use a router feature that fetches the code in parallel while the code is downloading. For example, React Router provides a `lazy` option to specify that a route should be code split and optimize when it is loaded: + +```js +import Home from './Home'; +import Dashboard from './Dashboard'; + +// ✅ Routes are downloaded before rendering +const router = createBrowserRouter([ + {path: '/', lazy: () => import('./Home')}, + {path: '/dashboard', lazy: () => import('Dashboard')} +]); +``` + +Optimized code-splitting is tricky to get right, and it's easy to make mistakes that can cause the user to download more code than they need. It works best when integrated with your router and data loading solutions to maximize caching, parallelize fetches, and support ["import on interaction"](https://www.patterns.dev/vanilla/import-on-interaction) patterns. + +### And more... {/*and-more*/} + +These are just a few examples of the limitations of Create React App. + +Once you've integrated routing, data-fetching, and code splitting, you now also need to consider pending states, navigation interruptions, error messages to the user, and revalidation of the data. There are entire categories of problems that users need to solve like: + +
+
    +
  • Accessibility
  • +
  • Asset loading
  • +
  • Authentication
  • +
  • Caching
  • +
+
    +
  • Error handling
  • +
  • Mutating data
  • +
  • Navigations
  • +
  • Optimistic updates
  • +
+
    +
  • Progressive enhancement
  • +
  • Server-side rendering
  • +
  • Static site generation
  • +
  • Streaming
  • +
+
+ +All of these work together to create the most optimal [loading sequence](https://www.patterns.dev/vanilla/loading-sequence). + +Solving each of these problems individually in Create React App can be difficult as each problem is interconnected with the others and can require deep expertise in problem areas users may not be familiar with. In order to solve these problems, users end up building their own bespoke solutions on top of Create React App, which was the problem Create React App originally tried to solve. + +## Why we Recommend Frameworks {/*why-we-recommend-frameworks*/} + +Although you could solve all these pieces yourself in a build tool like Create React App, Vite, or Parcel, it is hard to do well. Just like when Create React App itself integrated several build tools together, you need a tool to integrate all of these features together to provide the best experience to users. + +This category of tools that integrates build tools, rendering, routing, data fetching, and code splitting are known as "frameworks" -- or if you prefer to call React itself a framework, you might call them "metaframeworks". + +Frameworks impose some opinions about structuring your app in order to provide a much better user experience, in the same way build tools impose some opinions to make tooling easier. This is why we started recommending frameworks like [Next.js](https://nextjs.org/), [React Router](https://reactrouter.com/), and [Expo](https://expo.dev/) for new projects. + +Frameworks provide the same getting started experience as Create React App, but also provide solutions to problems users need to solve anyway in real production apps. + + + +#### Server rendering is optional {/*server-rendering-is-optional*/} + +The frameworks we recommend all provide the option to create a [client-side rendered (CSR)](https://developer.mozilla.org/en-US/docs/Glossary/CSR) app. + +In some cases, CSR is the right choice for a page, but many times it's not. Even if most of your app is client-side, there are often individual pages that could benefit from server rendering features like [static-site generation (SSG)](https://developer.mozilla.org/en-US/docs/Glossary/SSG) or [server-side rendering (SSR)](https://developer.mozilla.org/en-US/docs/Glossary/SSR), for example a Terms of Service page, or documentation. + +Server rendering generally sends less JavaScript to the client, and a full HTML document which produces a faster [First Contentful Paint (FCP)](https://web.dev/articles/fcp) by reducing [Total Blocking Time (TBD)](https://web.dev/articles/tbt), which can also lower [Interaction to Next Paint (INP)](https://web.dev/articles/inp). This is why the [Chrome team has encouraged](https://web.dev/articles/rendering-on-the-web) developers to consider static or server-side render over a full client-side approach to achieve the best possible performance. + +There are tradeoffs to using a server, and it is not always the best option for every page. Generating pages on the server incurs additional cost and takes time to generate which can increase [Time to First Byte (TTFB)](https://web.dev/articles/ttfb). The best performing apps are able to pick the right rendering strategy on a per-page basis, based on the tradeoffs of each strategy. + +Frameworks provide the option to use a server on any page if you want to, but do not force you to use a server. This allows you to pick the right rendering strategy for each page in your app. + +#### What About Server Components {/*server-components*/} + +The frameworks we recommend also include support for React Server Components. + +Server Components help solve these problems by moving routing and data fetching to the server, and allowing code splitting to be done for client components based on the data you render, instead of just the route rendered, and reducing the amount of JavaScript shipped for the best possible [loading sequence](https://www.patterns.dev/vanilla/loading-sequence). + +Server Components do not require a server. They can be run at build time on your CI server to create a static-site generated app (SSG) app, at runtime on a web server for a server-side rendered (SSR) app. + +See [Introducing zero-bundle size React Server Components](/blog/2020/12/21/data-fetching-with-react-server-components) and [the docs](/reference/rsc/server-components) for more info. + + + + + +#### Server Rendering is not just for SEO {/*server-rendering-is-not-just-for-seo*/} + +A common misunderstanding is that server rendering is only for [SEO](https://developer.mozilla.org/en-US/docs/Glossary/SEO). + +While server rendering can improve SEO, it also improves performance by reducing the amount of JavaScript the user needs to download and parse before they can see the content on the screen. + +This is why the Chrome team [has encouraged](https://web.dev/articles/rendering-on-the-web) developers to consider static or server-side render over a full client-side approach to achieve the best possible performance. + + + +--- + +_Thank you to [Dan Abramov](https://bsky.app/profile/danabra.mov) for creating Create React App, and [Joe Haddad](https://github.com/Timer), [Ian Schmitz](https://github.com/ianschmitz), [Brody McKee](https://github.com/mrmckeb), and [many others](https://github.com/facebook/create-react-app/graphs/contributors) for maintaining Create React App over the years. Thank you to [Brooks Lybrand](https://bsky.app/profile/brookslybrand.bsky.social), [Dan Abramov](https://bsky.app/profile/danabra.mov), [Devon Govett](https://bsky.app/profile/devongovett.bsky.social), [Eli White](https://x.com/Eli_White), [Jack Herrington](https://bsky.app/profile/jherr.dev), [Joe Savona](https://x.com/en_JS), [Lauren Tan](https://bsky.app/profile/no.lol), [Lee Robinson](https://x.com/leeerob), [Mark Erikson](https://bsky.app/profile/acemarke.dev), [Ryan Florance](https://x.com/ryanflorence), [Sophie Alpert](https://bsky.app/profile/sophiebits.com), [Tanner Linsley](https://bsky.app/profile/tannerlinsley.com), and [Theo Browne](https://x.com/theo) for reviewing and providing feedback on this post._ + diff --git a/src/content/blog/index.md b/src/content/blog/index.md index cc50b83c0..5cd4f35bd 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -4,12 +4,20 @@ title: React Blog -This blog is the official source for the updates from the React team. Anything important, including release notes or deprecation notices, will be posted here first. You can also follow the [@reactjs](https://twitter.com/reactjs) account on Twitter, but you won’t miss anything essential if you only read this blog. +This blog is the official source for the updates from the React team. Anything important, including release notes or deprecation notices, will be posted here first. + +You can also follow the [@react.dev](https://bsky.app/profiles/react.js) account on Bluesky, or [@reactjs](https://twitter.com/reactjs) account on Twitter, but you won’t miss anything essential if you only read this blog.
+ + +Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework. We’re also providing docs for when a framework isn’t a good fit for your project, or you prefer to start by building a framework. + + + In the React 19 Upgrade Guide, we shared step-by-step instructions for upgrading your app to React 19. In this post, we'll give an overview of the new features in React 19, and how you can adopt them ... diff --git a/src/content/learn/building-a-react-framework.md b/src/content/learn/building-a-react-framework.md new file mode 100644 index 000000000..131dd3947 --- /dev/null +++ b/src/content/learn/building-a-react-framework.md @@ -0,0 +1,127 @@ +--- +title: Building a React Framework +--- + + + +If your app has constraints not well-served by existing frameworks, or you prefer to solve these problems yourself, you can build your own framework. + + + + + +### Consider using an existing framework {/*you-should-probably-use-a-framework*/} + +Building a framework is complex and requires extensive expertise across various domains. This complexity is not limited to React — it is a widespread challenge encountered by all UI libraries. Using an existing framework can save significant time and effort by allowing you to focus on building your application. Existing frameworks have tested, robust features and community support. + +For a list of recommended frameworks, check out [Creating a React App](/learn/creating-a-react-app). + + + +Building a framework is a large undertaking that often requires expertise in many different areas. Understanding your goals and requirements before starting to build your own framework can help guide your development process and save a considerable amount of time. + +For example, if you need to build a framework that integrates with a specific system or infrastructure, it's important to understand the features and limitations of those systems. Understanding your constraints can help guide your framework development process. + +If you are building your own framework to learn, using popular tools like Vite and React Router can be a good starting point and let you focus on how to combine different tools to build a framework. + +## Step 1: Install a build tool {/*step-1-install-a-build-tool*/} + +The first step is to install a build tool like `vite` or `parcel`. These build tools provide features to package and run source code, provide a development server for local development and a build command to deploy your app to a production server. + +### Vite {/*vite*/} + +[Vite](https://vite.dev/) is a build tool that aims to provide a faster and leaner development experience for modern web projects. + + +npx vite@latest --template react + + +Vite is opinionated and comes with sensible defaults out of the box. Vite has a rich ecosystem of plugins to support fast refresh, JSX, Babel/SWC, and other common features. See Vite's [React plugin](https://vite.dev/plugins/#vitejs-plugin-react) or [React SWC plugin](https://vite.dev/plugins/#vitejs-plugin-react-swc) and [React SSR example project](https://vite.dev/guide/ssr.html#example-projects) to get started. + +Vite is already being used as a build tool in one of our [recommended frameworks](/learn/creating-a-react-app): [React Router](https://reactrouter.com/start/framework/installation). + +### Parcel {/*parcel*/} + +[Parcel](https://parceljs.org/) combines a great out-of-the-box development experience with a scalable architecture that can take your project from just getting started to massive production applications. + + +npm install --save-dev parcel + + +Parcel supports fast refresh, JSX, TypeScript, Flow, and styling out of the box. See [Parcel's React recipe](https://parceljs.org/recipes/react/#getting-started) to get started. + + + +#### Metro for React Native {/*react-native*/} + +If you'd like your framework to support React Native you'll need to use [Metro](https://metrobundler.dev/), the JavaScript bundler for React Native. Metro supports bundling for platforms like iOS and Android, but lacks many features when compared to Vite or Parcel. We recommend starting with Vite or Parcel unless your project requires React Native support. + + + +## Step 2: Build your framework {/*step-2-build-your-framework*/} + +The build tool you select starts with a client-only, single-page app (SPA). While SPAs can be a good place to start, many SPAs will encounter problems as they grow. Frameworks can provide the scaffolding to solve these problems. Most frameworks will implement routing, code-splitting, different rendering strategies, and data-fetching. These features are interconnected. For example, if you use a router that only works on the client it could prevent you from implementing server-side rendering. The best frameworks provide a cohesive, consistent experience across these features for developers and users. + +### Routing {/*routing*/} + +Routing determines what to display when a user visits a particular URL. You need to set up a router to map URLs to different parts of your app. You'll also need to handle nested routes, route parameters, and query parameters. Most modern routers use file-based routing. Routing can be integrated with other features like: + +* **Rendering strategies** to enable different rendering strategies on different routes, so you can introduce new strategies without having to rewrite your whole app. This can decrease the time it takes for the first byte of content to be loaded ([Time to First Byte](https://web.dev/articles/ttfb)), the first piece of content to be rendered ([First Contentful Paint](https://web.dev/articles/fcp)), and the largest visible content of the app to be rendered ([Largest Contentful Paint](https://web.dev/articles/lcp)). +* **Data fetching** to enable data fetching before the page loads on a route. This can prevent layout shifts ([Cumulative Layout Shift](https://web.dev/articles/cls)) and decrease the time it takes for the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/articles/lcp)) +* **Code splitting** to reduce the JavaScript bundle size sent to the client and improve performance on underpowered devices. This can reduce the time it takes for the browser to respond to a user interaction ([First Input Delay](https://web.dev/articles/fid)) and the largest visible content of the app to be rendered ([Largest Contentful Paint](https://web.dev/articles/lcp)). + +If you're not sure how to get started with routing, we recommend using [React Router](https://reactrouter.com/start/framework/custom) or [Tanstack Router](https://tanstack.com/router/latest). + +### Data-fetching {/*data-fetching*/} + +Data-fetching is the process of fetching data from a server or other data source. You need to set up or create a data-fetching library to handle data retrieval from your server and manage the state of that data. You'll also need to handle loading states, error states, and caching data. Data fetching can be integrated with features like: + +* **Routing** to enable data fetching to take place before page loads. This can improve how quickly a page loads and becomes visible to users ([Largest Contentful Paint](https://web.dev/lcp)) and reduce time it takes for your app to be interactive ([Time to Interactive](https://web.dev/tti)). +* **Rendering strategies** to prerender fetched data before it is sent to the client. This can reduce the time it takes for the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/lcp)). + +Integrating routing and data fetching is particularly important to prevent network waterfalls. In a SPA, if you fetch data during a component's initial render, the first data fetch is delayed until all code has loaded and components have finished rendering. This is commonly known as a waterfall: instead of fetching data at the same time as your code is loading, you need to first wait for your code to load before fetching data. To address these waterfalls, your app needs to fetch the data for each route in parallel with sending code to the browser. + +Popular data fetching libraries that you can use as a part of your framework include [React Query](https://react-query.tanstack.com/), [SWR](https://swr.vercel.app/), [Apollo](https://www.apollographql.com/docs/react), and [Relay](https://relay.dev/). + +### Rendering strategies {/*rendering-strategies*/} + +Since the build tool you select only support single page apps (SPAs) you'll need to implement other [rendering patterns](https://www.patterns.dev/vanilla/rendering-patterns) like server-side rendering (SSR), static site generation (SSG), and/or React Server Components (RSC). Even if you don't need these features at first, in the future there may be some routes that would benefit SSR, SSG or RSC. + +* **Single-page apps (SPA)** load a single HTML page and dynamically updates the page as the user interacts with the app. SPAs are fast and responsive, but they can have slower initial load times. SPAs are the default architecture for most build tools. + +* **Streaming Server-side rendering (SSR)** renders a page on the server and sends the fully rendered page to the client. SSR can improve performance, but it can be more complex to set up and maintain than a single-page app. With the addition of streaming, SSR can be very complex to set up and maintain. See [Vite's SSR guide]( https://vite.dev/guide/ssr). + +* **Static site generation (SSG)** generates static HTML files for your app at build time. SSG can improve performance, but it can be more complex to set up and maintain than server-side rendering. + +* **React Server Components (RSC)** lets you mix build-time, server-only, and interactive components in a single React tree. RSC can improve performance, but it currently requires deep expertise to set up and maintain. See [Parcel's RSC examples](https://github.com/parcel-bundler/rsc-examples). + +Your rendering strategies need to integrate with your router so apps built with your framework can choose the rendering strategy on a per-route level. This will enable different rendering strategies without having to rewrite your whole app. For example, the landing page for your app might benefit from being statically generated (SSG), while a page with a content feed might perform best with server-side rendering. Using the right rendering strategy for the right routes can decrease the time it takes for the first byte of content to be loaded ([Time to First Byte](https://web.dev/articles/ttfb)), the first piece of content to render ([First Contentful Paint](https://web.dev/articles/fcp)), and the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/articles/lcp)). + +### Code-splitting {/*code-splitting*/} + +Code-splitting is the process of breaking your app into smaller bundles that can be loaded on demand. An app's code size increases with every new feature and additional dependency. Apps can become slow to load because all of the code for the entire app needs to be sent before it can be used. Caching, reducing features/dependencies, and moving some code to run on the server can help mitigate slow loading but are incomplete solutions that can sacrifice functionality if overused. + +Similarly, if you rely on the apps using your framework to split the code, you might encounter situations where loading becomes slower than if no code splitting were happening at all. For example, [lazily loading](/reference/react/lazy) a chart delays sending the code needed to render the chart, splitting the chart code from the rest of the app. [Parcel supports code splitting with React.lazy](https://parceljs.org/recipes/react/#code-splitting). However, if the chart loads its data *after* it has been initially rendered you are now waiting twice. This is a waterfall: rather than fetching the data for the chart and sending the code to render it simultaneously, you must wait for each step to complete one after the other. + +Splitting code by route, when integrated with bundling and data fetching, can reduce the initial load time of your app and the time it takes for the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/articles/lcp)). + +### And more... {/*and-more*/} + +These are just a few examples of the features a framework will need to consider. + +There are many other problems that users need to solve like: + +- Accessibility +- Asset loading +- Authentication +- Error handling +- Mutating data +- Navigations +- Nested routes +- Optimistic updates +- Caching +- Progressive enhancement +- Static site generation +- Server-side rendering + +Many of these problems individually can be difficult as each problem is interconnected with the others and can require deep expertise in problem areas you may not be familiar with. If you don't want to solve these problems on your own, you can [get started with a framework](/learn/creating-a-react-app) that provides these features out of the box. diff --git a/src/content/learn/creating-a-react-app.md b/src/content/learn/creating-a-react-app.md new file mode 100644 index 000000000..cf7359e45 --- /dev/null +++ b/src/content/learn/creating-a-react-app.md @@ -0,0 +1,116 @@ +--- +title: Creating a React App +--- + + + +If you want to build a new app or website with React, we recommend starting with a framework. + + + +## Recommended React frameworks {/*bleeding-edge-react-frameworks*/} + +These recommended frameworks support all the features you need to deploy and scale your app in production. They have integrated the latest React features and take advantage of React’s architecture. + + + +#### React frameworks do not require a server. {/*react-frameworks-do-not-require-a-server*/} + +All the frameworks on this page can create single-page apps. Single-page apps can be deployed to a [CDN](https://developer.mozilla.org/en-US/docs/Glossary/CDN) or static hosting service and do not need a server. If you would like to enable features that require a server (like server side rendering), you can opt-in on individual routes without rewriting your app. + + + +### Next.js (App Router) {/*nextjs-app-router*/} + +**[Next.js's App Router](https://nextjs.org/docs) is a React framework that takes full advantage of React's architecture to enable full-stack React apps.** + + +npx create-next-app@latest + + +Next.js is maintained by [Vercel](https://vercel.com/). You can [deploy a Next.js app](https://nextjs.org/docs/app/building-your-application/deploying) to any Node.js or serverless hosting, or to your own server. Next.js also supports [static export](https://nextjs.org/docs/app/building-your-application/deploying/static-exports) which doesn't require a server. Vercel additionally provides opt-in paid cloud services. + +### React Router (v7) {/*react-router-v7*/} + +**[React Router](https://reactrouter.com/start/framework/installation) is the most popular routing library for React and can be paired with Vite to create a full-stack React framework**. It emphasizes standard Web APIs and has several [ready to deploy templates](https://github.com/remix-run/react-router-templates) for various JavaScript runtimes and platforms. + +To create a new React Router framework project, run: + + +npx create-react-router@latest + + +React Router is maintained by [Shopify](https://www.shopify.com). + +### Expo (for native apps) {/*expo*/} + +**[Expo](https://expo.dev/) is a React framework that lets you create universal Android, iOS, and web apps with truly native UIs.** It provides an SDK for [React Native](https://reactnative.dev/) that makes the native parts easier to use. To create a new Expo project, run: + + +npx create-expo-app@latest + + +If you're new to Expo, check out the [Expo tutorial](https://docs.expo.dev/tutorial/introduction/). + +Expo is maintained by [Expo (the company)](https://expo.dev/about). Building apps with Expo is free, and you can submit them to the Google and Apple app stores without restrictions. Expo additionally provides opt-in paid cloud services. + + +## Other options {/*other-options*/} + +There are other up-and-coming frameworks that are working towards our full stack React vision: + +- [TanStack Start (Beta)](https://tanstack.com/): TanStack Start is a full-stack React framework powered by TanStack Router. It provides a full-document SSR, streaming, server functions, bundling, and more using tools like Nitro and Vite. +- [RedwoodJS](https://redwoodjs.com/): Redwood is a full stack React framework with lots of pre-installed packages and configuration that makes it easy to build full-stack web applications. + + + +#### Which features make up the React team’s full-stack architecture vision? {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} + +Next.js's App Router bundler fully implements the official [React Server Components specification](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md). This lets you mix build-time, server-only, and interactive components in a single React tree. + +For example, you can write a server-only React component as an `async` function that reads from a database or from a file. Then you can pass data down from it to your interactive components: + +```js +// This component runs *only* on the server (or during the build). +async function Talks({ confId }) { + // 1. You're on the server, so you can talk to your data layer. API endpoint not required. + const talks = await db.Talks.findAll({ confId }); + + // 2. Add any amount of rendering logic. It won't make your JavaScript bundle larger. + const videos = talks.map(talk => talk.video); + + // 3. Pass the data down to the components that will run in the browser. + return ; +} +``` + +Next.js's App Router also integrates [data fetching with Suspense](/blog/2022/03/29/react-v18#suspense-in-data-frameworks). This lets you specify a loading state (like a skeleton placeholder) for different parts of your user interface directly in your React tree: + +```js +}> + + +``` + +Server Components and Suspense are React features rather than Next.js features. However, adopting them at the framework level requires buy-in and non-trivial implementation work. At the moment, the Next.js App Router is the most complete implementation. The React team is working with bundler developers to make these features easier to implement in the next generation of frameworks. + + + + + + +#### Do you recommend Vite? {/*do-you-recommend-vite*/} + +We provide several Vite-based recommendations. + +React Router v7 is a Vite based framework which allows you to use Vite's fast development server and build tooling with a framework that provides routing and data fetching. Just like the other frameworks we recommend, you can build a SPA with React Router v7. + +We also recommend using Vite when [adding React to an existing project](/learn/add-react-to-an-existing-project), or [building a framework](/learn/building-a-react-framework). + +Just like Svelte has Sveltekit, Vue has Nuxt, and Solid has SolidStart, React recommends using a framework that integrates with build tools like Vite for new projects. + + + +----- + +_If you’re a framework author interested in being included on this page, [please let us know](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+)._ \ No newline at end of file diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 7251fc31b..8ad019c7e 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -8,15 +8,6 @@ React has been designed from the start for gradual adoption. You can use as litt - - -* [How to start a new React project](/learn/start-a-new-react-project) -* [How to add React to an existing project](/learn/add-react-to-an-existing-project) -* [How to set up your editor](/learn/editor-setup) -* [How to install React Developer Tools](/learn/react-developer-tools) - - - ## Try React {/*try-react*/} You don't need to install anything to play with React. Try editing this sandbox! @@ -39,17 +30,27 @@ You can edit it directly or open it in a new tab by pressing the "Fork" button i Most pages in the React documentation contain sandboxes like this. Outside of the React documentation, there are many online sandboxes that support React: for example, [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react), or [CodePen.](https://codepen.io/pen?template=QWYVwWN) -### Try React locally {/*try-react-locally*/} - To try React locally on your computer, [download this HTML page.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Open it in your editor and in your browser! -## Start a new React project {/*start-a-new-react-project*/} +## Creating a React App {/*creating-a-react-app*/} + +If you want to start a new React app, you can [create a React app](/learn/creating-a-react-app) using a recommended framework. -If you want to build an app or a website fully with React, [start a new React project.](/learn/start-a-new-react-project) +## Build a React Framework {/*build-a-react-framework*/} + +If a framework is not a good fit for your project, or you prefer to start by building your own framework, you can [build your own React framework](/learn/building-a-react-framework). ## Add React to an existing project {/*add-react-to-an-existing-project*/} -If want to try using React in your existing app or a website, [add React to an existing project.](/learn/add-react-to-an-existing-project) +If want to try using React in your existing app or a website, you can [add React to an existing project.](/learn/add-react-to-an-existing-project) + +## Deprecated Options {/*deprecated-options*/} + +### Create React App (Deprecated) {/*create-react-app-deprecated*/} + +Create React App is a deprecated tool, previously recommended for creating new React apps. If you want to start a new React app, you can [create a React app](/learn/creat-a-react-app) using a recommended framework. + +For more information, see [Sunsetting Create React App](/blog/2025/02/14/sunsetting-create-react-app). ## Next steps {/*next-steps*/} diff --git a/src/content/learn/setup.md b/src/content/learn/setup.md new file mode 100644 index 000000000..84608b427 --- /dev/null +++ b/src/content/learn/setup.md @@ -0,0 +1,32 @@ +--- +title: Setup +--- + + +React integrates with tools like editors, TypeScript, browser extensions, and compliers. This section will help you get your environment set up. + + + +## Editor Setup {/*editor-setup*/} + +See our [recommended editors](/learn/editor-setup) and learn how to set them up to work with React. + +## Using TypeScript {/*using-typescript*/} + +TypeScript is a popular way to add type definitions to JavaScript codebases. [Learn how to integrate TypeScript into your React projects](/learn/typescript). + +## React Developer Tools {/*react-developer-tools*/} + +React Developer Tools is a browser extension that can inspect React components, edit props and state, and identify performance problems. Learn how to install it [here](learn/react-developer-tools). + +## React Compiler {/*react-compiler*/} + +React Compiler is a tool that automatically optimizes your React app. [Learn more](/learn/react-compiler). + +## Start a React Project from scratch {/*start-a-react-project-from-scratch*/} + +If you want to build your own framework, you can [start a React project from scratch](/learn/start-a-react-project-from-scratch). + +## Next steps {/*next-steps*/} + +Head to the [Quick Start](/learn) guide for a tour of the most important React concepts you will encounter every day. diff --git a/src/content/learn/start-a-new-react-project.md b/src/content/learn/start-a-new-react-project.md deleted file mode 100644 index 1eb263618..000000000 --- a/src/content/learn/start-a-new-react-project.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Start a New React Project ---- - - - -If you want to build a new app or a new website fully with React, we recommend picking one of the React-powered frameworks popular in the community. - - - - -You can use React without a framework, however we’ve found that most apps and sites eventually build solutions to common problems such as code-splitting, routing, data fetching, and generating HTML. These problems are common to all UI libraries, not just React. - -By starting with a framework, you can get started with React quickly, and avoid essentially building your own framework later. - - - -#### Can I use React without a framework? {/*can-i-use-react-without-a-framework*/} - -You can definitely use React without a framework--that's how you'd [use React for a part of your page.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) **However, if you're building a new app or a site fully with React, we recommend using a framework.** - -Here's why. - -Even if you don't need routing or data fetching at first, you'll likely want to add some libraries for them. As your JavaScript bundle grows with every new feature, you might have to figure out how to split code for every route individually. As your data fetching needs get more complex, you are likely to encounter server-client network waterfalls that make your app feel very slow. As your audience includes more users with poor network conditions and low-end devices, you might need to generate HTML from your components to display content early--either on the server, or during the build time. Changing your setup to run some of your code on the server or during the build can be very tricky. - -**These problems are not React-specific. This is why Svelte has SvelteKit, Vue has Nuxt, and so on.** To solve these problems on your own, you'll need to integrate your bundler with your router and with your data fetching library. It's not hard to get an initial setup working, but there are a lot of subtleties involved in making an app that loads quickly even as it grows over time. You'll want to send down the minimal amount of app code but do so in a single client–server roundtrip, in parallel with any data required for the page. You'll likely want the page to be interactive before your JavaScript code even runs, to support progressive enhancement. You may want to generate a folder of fully static HTML files for your marketing pages that can be hosted anywhere and still work with JavaScript disabled. Building these capabilities yourself takes real work. - -**React frameworks on this page solve problems like these by default, with no extra work from your side.** They let you start very lean and then scale your app with your needs. Each React framework has a community, so finding answers to questions and upgrading tooling is easier. Frameworks also give structure to your code, helping you and others retain context and skills between different projects. Conversely, with a custom setup it's easier to get stuck on unsupported dependency versions, and you'll essentially end up creating your own framework—albeit one with no community or upgrade path (and if it's anything like the ones we've made in the past, more haphazardly designed). - -If your app has unusual constraints not served well by these frameworks, or you prefer to solve these problems yourself, you can roll your own custom setup with React. Grab `react` and `react-dom` from npm, set up your custom build process with a bundler like [Vite](https://vite.dev/) or [Parcel](https://parceljs.org/), and add other tools as you need them for routing, static generation or server-side rendering, and more. - - - -## Production-grade React frameworks {/*production-grade-react-frameworks*/} - -These frameworks support all the features you need to deploy and scale your app in production and are working towards supporting our [full-stack architecture vision](#which-features-make-up-the-react-teams-full-stack-architecture-vision). All of the frameworks we recommend are open source with active communities for support, and can be deployed to your own server or a hosting provider. If you’re a framework author interested in being included on this list, [please let us know](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+). - -### Next.js {/*nextjs-pages-router*/} - -**[Next.js' Pages Router](https://nextjs.org/) is a full-stack React framework.** It's versatile and lets you create React apps of any size--from a mostly static blog to a complex dynamic application. To create a new Next.js project, run in your terminal: - - -npx create-next-app@latest - - -If you're new to Next.js, check out the [learn Next.js course.](https://nextjs.org/learn) - -Next.js is maintained by [Vercel](https://vercel.com/). You can [deploy a Next.js app](https://nextjs.org/docs/app/building-your-application/deploying) to any Node.js or serverless hosting, or to your own server. Next.js also supports a [static export](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports) which doesn't require a server. - -### Remix {/*remix*/} - -**[Remix](https://remix.run/) is a full-stack React framework with nested routing.** It lets you break your app into nested parts that can load data in parallel and refresh in response to the user actions. To create a new Remix project, run: - - -npx create-remix - - -If you're new to Remix, check out the Remix [blog tutorial](https://remix.run/docs/en/main/tutorials/blog) (short) and [app tutorial](https://remix.run/docs/en/main/tutorials/jokes) (long). - -Remix is maintained by [Shopify](https://www.shopify.com/). When you create a Remix project, you need to [pick your deployment target](https://remix.run/docs/en/main/guides/deployment). You can deploy a Remix app to any Node.js or serverless hosting by using or writing an [adapter](https://remix.run/docs/en/main/other-api/adapter). - -### Gatsby {/*gatsby*/} - -**[Gatsby](https://www.gatsbyjs.com/) is a React framework for fast CMS-backed websites.** Its rich plugin ecosystem and its GraphQL data layer simplify integrating content, APIs, and services into one website. To create a new Gatsby project, run: - - -npx create-gatsby - - -If you're new to Gatsby, check out the [Gatsby tutorial.](https://www.gatsbyjs.com/docs/tutorial/) - -Gatsby is maintained by [Netlify](https://www.netlify.com/). You can [deploy a fully static Gatsby site](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting) to any static hosting. If you opt into using server-only features, make sure your hosting provider supports them for Gatsby. - -### Expo (for native apps) {/*expo*/} - -**[Expo](https://expo.dev/) is a React framework that lets you create universal Android, iOS, and web apps with truly native UIs.** It provides an SDK for [React Native](https://reactnative.dev/) that makes the native parts easier to use. To create a new Expo project, run: - - -npx create-expo-app - - -If you're new to Expo, check out the [Expo tutorial](https://docs.expo.dev/tutorial/introduction/). - -Expo is maintained by [Expo (the company)](https://expo.dev/about). Building apps with Expo is free, and you can submit them to the Google and Apple app stores without restrictions. Expo additionally provides opt-in paid cloud services. - -## Bleeding-edge React frameworks {/*bleeding-edge-react-frameworks*/} - -As we've explored how to continue improving React, we realized that integrating React more closely with frameworks (specifically, with routing, bundling, and server technologies) is our biggest opportunity to help React users build better apps. The Next.js team has agreed to collaborate with us in researching, developing, integrating, and testing framework-agnostic bleeding-edge React features like [React Server Components.](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) - -These features are getting closer to being production-ready every day, and we've been in talks with other bundler and framework developers about integrating them. Our hope is that in a year or two, all frameworks listed on this page will have full support for these features. (If you're a framework author interested in partnering with us to experiment with these features, please let us know!) - -### Next.js (App Router) {/*nextjs-app-router*/} - -**[Next.js's App Router](https://nextjs.org/docs) is a redesign of the Next.js APIs aiming to fulfill the React team’s full-stack architecture vision.** It lets you fetch data in asynchronous components that run on the server or even during the build. - -Next.js is maintained by [Vercel](https://vercel.com/). You can [deploy a Next.js app](https://nextjs.org/docs/app/building-your-application/deploying) to any Node.js or serverless hosting, or to your own server. Next.js also supports [static export](https://nextjs.org/docs/app/building-your-application/deploying/static-exports) which doesn't require a server. - - - -#### Which features make up the React team’s full-stack architecture vision? {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} - -Next.js's App Router bundler fully implements the official [React Server Components specification](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md). This lets you mix build-time, server-only, and interactive components in a single React tree. - -For example, you can write a server-only React component as an `async` function that reads from a database or from a file. Then you can pass data down from it to your interactive components: - -```js -// This component runs *only* on the server (or during the build). -async function Talks({ confId }) { - // 1. You're on the server, so you can talk to your data layer. API endpoint not required. - const talks = await db.Talks.findAll({ confId }); - - // 2. Add any amount of rendering logic. It won't make your JavaScript bundle larger. - const videos = talks.map(talk => talk.video); - - // 3. Pass the data down to the components that will run in the browser. - return ; -} -``` - -Next.js's App Router also integrates [data fetching with Suspense](/blog/2022/03/29/react-v18#suspense-in-data-frameworks). This lets you specify a loading state (like a skeleton placeholder) for different parts of your user interface directly in your React tree: - -```js -}> - - -``` - -Server Components and Suspense are React features rather than Next.js features. However, adopting them at the framework level requires buy-in and non-trivial implementation work. At the moment, the Next.js App Router is the most complete implementation. The React team is working with bundler developers to make these features easier to implement in the next generation of frameworks. - - diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 335fc3556..7471eb20c 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -25,13 +25,23 @@ "path": "/learn/installation", "routes": [ { - "title": "Start a New React Project", - "path": "/learn/start-a-new-react-project" + "title": "Creating a React App", + "path": "/learn/creating-a-react-app" + }, + { + "title": "Building a React Framework", + "path": "/learn/building-a-react-framework" }, { "title": "Add React to an Existing Project", "path": "/learn/add-react-to-an-existing-project" - }, + } + ] + }, + { + "title": "Setup", + "path": "/learn/setup", + "routes": [ { "title": "Editor Setup", "path": "/learn/editor-setup" diff --git a/tsconfig.json b/tsconfig.json index 440b38510..9d72e01bc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,12 +22,18 @@ "isolatedModules": true, "jsx": "preserve", "baseUrl": "src", - "incremental": true + "incremental": true, + "plugins": [ + { + "name": "next" + } + ] }, "include": [ "next-env.d.ts", "src/**/*.ts", - "src/**/*.tsx" + "src/**/*.tsx", + ".next/types/**/*.ts" ], "exclude": [ "node_modules" diff --git a/vercel.json b/vercel.json index e08fda745..fdd63f5bb 100644 --- a/vercel.json +++ b/vercel.json @@ -164,6 +164,11 @@ "destination": "https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html", "permanent": false }, + { + "source": "/link/cra", + "destination": "/blog/2025/02/14/sunsetting-create-react-app", + "permanent": false + }, { "source": "/warnings/version-mismatch", "destination": "/warnings/invalid-hook-call-warning#mismatching-versions-of-react-and-react-dom", @@ -224,6 +229,11 @@ "destination": "https://18.react.dev/reference/react-dom/server/renderToNodeStream", "permanent": true }, + { + "source": "/learn/start-a-new-react-project", + "destination": "/learn/creating-a-react-app", + "permanent": true + }, { "source": "/blog/2024/04/25/react-19", "destination": "/blog/2024/12/05/react-19", From 3ba4f8cee38738981c0a020f6b06e48850594af5 Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 14 Feb 2025 14:14:56 -0500 Subject: [PATCH 010/139] Fix misspelling in cra blog post (#7496) --- .../2025/02/14/sunsetting-create-react-app.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/content/blog/2025/02/14/sunsetting-create-react-app.md b/src/content/blog/2025/02/14/sunsetting-create-react-app.md index 22dd491e3..113dfa5e8 100644 --- a/src/content/blog/2025/02/14/sunsetting-create-react-app.md +++ b/src/content/blog/2025/02/14/sunsetting-create-react-app.md @@ -17,7 +17,7 @@ Today, we’re deprecating [Create React App](https://create-react-app.dev/) for ----- -When we released Create React App in 2016, there was no clear way to build a new React app. +When we released Create React App in 2016, there was no clear way to build a new React app. To create a React app, you had to install a bunch of tools and wire them up together yourself to support basic features like JSX, linting, and hot reloading. This was very tricky to do correctly, so the [community](https://github.com/react-boilerplate/react-boilerplate) [created](https://github.com/kriasoft/react-starter-kit) [boilerplates](https://github.com/petehunt/react-boilerplate) for [common](https://github.com/gaearon/react-hot-boilerplate) [setups](https://github.com/erikras/react-redux-universal-hot-example). However, boilerplates were difficult to update and fragmentation made it difficult for React to release new features. @@ -38,7 +38,7 @@ Starting today, if you install a new app, you will see a deprecation warning: create-react-app is deprecated. {'\n\n'} -You can find a list of up-to-date React frameworks on react.dev +You can find a list of up-to-date React frameworks on react.dev For more info see: react.dev/link/cra {'\n\n'} This error message will only be shown once per install. @@ -56,7 +56,7 @@ For existing apps, these guides will help you migrate to a client-only SPA: Create React App will continue working in maintenance mode, and we've published a new version of Create React App to work with React 19. -If your app has unusual constraints, or you prefer to solve these problems by building your own framework, or you just want to learn how react works from scratch, you can roll your own custom setup with React using Vite or Parcel. +If your app has unusual constraints, or you prefer to solve these problems by building your own framework, or you just want to learn how react works from scratch, you can roll your own custom setup with React using Vite or Parcel. To help users get started with Vite or Parcel, we've published new docs for [Building a Framework](/learn/building-a-react-framework). Continue reading to learn more about the [limitations of Create React App](#limitations-of-create-react-app) and [why we recommend frameworks](#why-we-recommend-frameworks). @@ -90,7 +90,7 @@ export default function App() { } ``` -This allows you to immediately start coding in React with features like JSX, default linting rules, and a bundler to run in both development and production. However, this setup is missing the tools you need to build a real production app. +This allows you to immediately start coding in React with features like JSX, default linting rules, and a bundler to run in both development and production. However, this setup is missing the tools you need to build a real production app. Most production apps need solutions to problems like routing, data fetching, and code splitting. @@ -143,21 +143,21 @@ There's a tradeoff being made here: the routing library adds complexity to the a ### Data Fetching {/*data-fetching*/} -Another common problem in Create React App is data fetching. Create React App does not include a specific data fetching solution. If you're just getting started, a common option is to use `fetch` in an effect to load data. +Another common problem in Create React App is data fetching. Create React App does not include a specific data fetching solution. If you're just getting started, a common option is to use `fetch` in an effect to load data. But doing this means that the data is fetched after the component renders, which can cause network waterfalls. Network waterfalls are caused by fetching data when your app renders instead of in parallel while the code is downloading: ```js export default function Dashboard() { const [data, setData] = useState(null); - + // ❌ Fetching data in a component causes network waterfalls useEffect(() => { fetch('/api/data') .then(response => response.json()) .then(data => setData(data)); }, []); - + return (
{data.map(item =>
{item.name}
)} @@ -193,18 +193,18 @@ However, this requires correctly configuring the loaders in your app and trades ### Code Splitting {/*code-splitting*/} -Another common problem in Create React App is [code splitting](https://www.patterns.dev/vanilla/bundle-splitting). Create React App does not include a specific code splitting solution. If you're just getting started, you might not consider code splitting at all. +Another common problem in Create React App is [code splitting](https://www.patterns.dev/vanilla/bundle-splitting). Create React App does not include a specific code splitting solution. If you're just getting started, you might not consider code splitting at all. This means your app is shipped as a single bundle: ```txt - bundle.js 75kb ``` - + But for ideal performance, you should "split" your code into separate bundles so the user only needs to download what they need. This decreases the time the user needs to wait to load your app, by only downloading the code they need to see the page they are on. ```txt -- core.js 25kb +- core.js 25kb - home.js 25kb - dashboard.js 25kb ``` @@ -226,7 +226,7 @@ Optimized code-splitting is tricky to get right, and it's easy to make mistakes ### And more... {/*and-more*/} -These are just a few examples of the limitations of Create React App. +These are just a few examples of the limitations of Create React App. Once you've integrated routing, data-fetching, and code splitting, you now also need to consider pending states, navigation interruptions, error messages to the user, and revalidation of the data. There are entire categories of problems that users need to solve like: @@ -251,7 +251,7 @@ Once you've integrated routing, data-fetching, and code splitting, you now also
-All of these work together to create the most optimal [loading sequence](https://www.patterns.dev/vanilla/loading-sequence). +All of these work together to create the most optimal [loading sequence](https://www.patterns.dev/vanilla/loading-sequence). Solving each of these problems individually in Create React App can be difficult as each problem is interconnected with the others and can require deep expertise in problem areas users may not be familiar with. In order to solve these problems, users end up building their own bespoke solutions on top of Create React App, which was the problem Create React App originally tried to solve. @@ -259,7 +259,7 @@ Solving each of these problems individually in Create React App can be difficult Although you could solve all these pieces yourself in a build tool like Create React App, Vite, or Parcel, it is hard to do well. Just like when Create React App itself integrated several build tools together, you need a tool to integrate all of these features together to provide the best experience to users. -This category of tools that integrates build tools, rendering, routing, data fetching, and code splitting are known as "frameworks" -- or if you prefer to call React itself a framework, you might call them "metaframeworks". +This category of tools that integrates build tools, rendering, routing, data fetching, and code splitting are known as "frameworks" -- or if you prefer to call React itself a framework, you might call them "metaframeworks". Frameworks impose some opinions about structuring your app in order to provide a much better user experience, in the same way build tools impose some opinions to make tooling easier. This is why we started recommending frameworks like [Next.js](https://nextjs.org/), [React Router](https://reactrouter.com/), and [Expo](https://expo.dev/) for new projects. @@ -269,7 +269,7 @@ Frameworks provide the same getting started experience as Create React App, but #### Server rendering is optional {/*server-rendering-is-optional*/} -The frameworks we recommend all provide the option to create a [client-side rendered (CSR)](https://developer.mozilla.org/en-US/docs/Glossary/CSR) app. +The frameworks we recommend all provide the option to create a [client-side rendered (CSR)](https://developer.mozilla.org/en-US/docs/Glossary/CSR) app. In some cases, CSR is the right choice for a page, but many times it's not. Even if most of your app is client-side, there are often individual pages that could benefit from server rendering features like [static-site generation (SSG)](https://developer.mozilla.org/en-US/docs/Glossary/SSG) or [server-side rendering (SSR)](https://developer.mozilla.org/en-US/docs/Glossary/SSR), for example a Terms of Service page, or documentation. @@ -285,7 +285,7 @@ The frameworks we recommend also include support for React Server Components. Server Components help solve these problems by moving routing and data fetching to the server, and allowing code splitting to be done for client components based on the data you render, instead of just the route rendered, and reducing the amount of JavaScript shipped for the best possible [loading sequence](https://www.patterns.dev/vanilla/loading-sequence). -Server Components do not require a server. They can be run at build time on your CI server to create a static-site generated app (SSG) app, at runtime on a web server for a server-side rendered (SSR) app. +Server Components do not require a server. They can be run at build time on your CI server to create a static-site generated app (SSG) app, at runtime on a web server for a server-side rendered (SSR) app. See [Introducing zero-bundle size React Server Components](/blog/2020/12/21/data-fetching-with-react-server-components) and [the docs](/reference/rsc/server-components) for more info. @@ -295,9 +295,9 @@ See [Introducing zero-bundle size React Server Components](/blog/2020/12/21/data #### Server Rendering is not just for SEO {/*server-rendering-is-not-just-for-seo*/} -A common misunderstanding is that server rendering is only for [SEO](https://developer.mozilla.org/en-US/docs/Glossary/SEO). +A common misunderstanding is that server rendering is only for [SEO](https://developer.mozilla.org/en-US/docs/Glossary/SEO). -While server rendering can improve SEO, it also improves performance by reducing the amount of JavaScript the user needs to download and parse before they can see the content on the screen. +While server rendering can improve SEO, it also improves performance by reducing the amount of JavaScript the user needs to download and parse before they can see the content on the screen. This is why the Chrome team [has encouraged](https://web.dev/articles/rendering-on-the-web) developers to consider static or server-side render over a full client-side approach to achieve the best possible performance. @@ -305,5 +305,5 @@ This is why the Chrome team [has encouraged](https://web.dev/articles/rendering- --- -_Thank you to [Dan Abramov](https://bsky.app/profile/danabra.mov) for creating Create React App, and [Joe Haddad](https://github.com/Timer), [Ian Schmitz](https://github.com/ianschmitz), [Brody McKee](https://github.com/mrmckeb), and [many others](https://github.com/facebook/create-react-app/graphs/contributors) for maintaining Create React App over the years. Thank you to [Brooks Lybrand](https://bsky.app/profile/brookslybrand.bsky.social), [Dan Abramov](https://bsky.app/profile/danabra.mov), [Devon Govett](https://bsky.app/profile/devongovett.bsky.social), [Eli White](https://x.com/Eli_White), [Jack Herrington](https://bsky.app/profile/jherr.dev), [Joe Savona](https://x.com/en_JS), [Lauren Tan](https://bsky.app/profile/no.lol), [Lee Robinson](https://x.com/leeerob), [Mark Erikson](https://bsky.app/profile/acemarke.dev), [Ryan Florance](https://x.com/ryanflorence), [Sophie Alpert](https://bsky.app/profile/sophiebits.com), [Tanner Linsley](https://bsky.app/profile/tannerlinsley.com), and [Theo Browne](https://x.com/theo) for reviewing and providing feedback on this post._ +_Thank you to [Dan Abramov](https://bsky.app/profile/danabra.mov) for creating Create React App, and [Joe Haddad](https://github.com/Timer), [Ian Schmitz](https://github.com/ianschmitz), [Brody McKee](https://github.com/mrmckeb), and [many others](https://github.com/facebook/create-react-app/graphs/contributors) for maintaining Create React App over the years. Thank you to [Brooks Lybrand](https://bsky.app/profile/brookslybrand.bsky.social), [Dan Abramov](https://bsky.app/profile/danabra.mov), [Devon Govett](https://bsky.app/profile/devongovett.bsky.social), [Eli White](https://x.com/Eli_White), [Jack Herrington](https://bsky.app/profile/jherr.dev), [Joe Savona](https://x.com/en_JS), [Lauren Tan](https://bsky.app/profile/no.lol), [Lee Robinson](https://x.com/leeerob), [Mark Erikson](https://bsky.app/profile/acemarke.dev), [Ryan Florence](https://x.com/ryanflorence), [Sophie Alpert](https://bsky.app/profile/sophiebits.com), [Tanner Linsley](https://bsky.app/profile/tannerlinsley.com), and [Theo Browne](https://x.com/theo) for reviewing and providing feedback on this post._ From 294c731369875e43d526f5c641c02971db95a51d Mon Sep 17 00:00:00 2001 From: Otabek Shoyimov Date: Mon, 17 Feb 2025 00:41:47 +0500 Subject: [PATCH 011/139] fix(docs): wrong redirect link to /learn/creating-a-react-app on Create React App (Depreacted) page section (#7612) --- src/content/learn/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 8ad019c7e..f9a5b10fd 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -48,7 +48,7 @@ If want to try using React in your existing app or a website, you can [add React ### Create React App (Deprecated) {/*create-react-app-deprecated*/} -Create React App is a deprecated tool, previously recommended for creating new React apps. If you want to start a new React app, you can [create a React app](/learn/creat-a-react-app) using a recommended framework. +Create React App is a deprecated tool, previously recommended for creating new React apps. If you want to start a new React app, you can [create a React app](/learn/creating-a-react-app) using a recommended framework. For more information, see [Sunsetting Create React App](/blog/2025/02/14/sunsetting-create-react-app). From c438e9a881b2f86f50c206157cc9088b4caf488a Mon Sep 17 00:00:00 2001 From: elitalpa Date: Sun, 16 Feb 2025 20:43:15 +0100 Subject: [PATCH 012/139] fix(docs): wrong vite command (#7615) --- src/content/learn/building-a-react-framework.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/building-a-react-framework.md b/src/content/learn/building-a-react-framework.md index 131dd3947..14d100df6 100644 --- a/src/content/learn/building-a-react-framework.md +++ b/src/content/learn/building-a-react-framework.md @@ -33,7 +33,7 @@ The first step is to install a build tool like `vite` or `parcel`. These build t [Vite](https://vite.dev/) is a build tool that aims to provide a faster and leaner development experience for modern web projects. -npx vite@latest --template react +npm create vite@latest my-app -- --template react Vite is opinionated and comes with sensible defaults out of the box. Vite has a rich ecosystem of plugins to support fast refresh, JSX, Babel/SWC, and other common features. See Vite's [React plugin](https://vite.dev/plugins/#vitejs-plugin-react) or [React SWC plugin](https://vite.dev/plugins/#vitejs-plugin-react-swc) and [React SSR example project](https://vite.dev/guide/ssr.html#example-projects) to get started. From 49284218b1f5c94f930f8a9b305040dbe7d3dd48 Mon Sep 17 00:00:00 2001 From: neverland Date: Mon, 17 Feb 2025 03:52:28 +0800 Subject: [PATCH 013/139] Add Rsbuild as a build tool for React projects (#7608) --- .../blog/2025/02/14/sunsetting-create-react-app.md | 4 ++-- src/content/learn/building-a-react-framework.md | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/content/blog/2025/02/14/sunsetting-create-react-app.md b/src/content/blog/2025/02/14/sunsetting-create-react-app.md index 113dfa5e8..531d9c9f6 100644 --- a/src/content/blog/2025/02/14/sunsetting-create-react-app.md +++ b/src/content/blog/2025/02/14/sunsetting-create-react-app.md @@ -56,9 +56,9 @@ For existing apps, these guides will help you migrate to a client-only SPA: Create React App will continue working in maintenance mode, and we've published a new version of Create React App to work with React 19. -If your app has unusual constraints, or you prefer to solve these problems by building your own framework, or you just want to learn how react works from scratch, you can roll your own custom setup with React using Vite or Parcel. +If your app has unusual constraints, or you prefer to solve these problems by building your own framework, or you just want to learn how react works from scratch, you can roll your own custom setup with React using Vite, Parcel or Rsbuild. -To help users get started with Vite or Parcel, we've published new docs for [Building a Framework](/learn/building-a-react-framework). Continue reading to learn more about the [limitations of Create React App](#limitations-of-create-react-app) and [why we recommend frameworks](#why-we-recommend-frameworks). +To help users get started with Vite, Parcel or Rsbuild, we've published new docs for [Building a Framework](/learn/building-a-react-framework). Continue reading to learn more about the [limitations of Create React App](#limitations-of-create-react-app) and [why we recommend frameworks](#why-we-recommend-frameworks). diff --git a/src/content/learn/building-a-react-framework.md b/src/content/learn/building-a-react-framework.md index 14d100df6..50e34ff65 100644 --- a/src/content/learn/building-a-react-framework.md +++ b/src/content/learn/building-a-react-framework.md @@ -26,7 +26,7 @@ If you are building your own framework to learn, using popular tools like Vite a ## Step 1: Install a build tool {/*step-1-install-a-build-tool*/} -The first step is to install a build tool like `vite` or `parcel`. These build tools provide features to package and run source code, provide a development server for local development and a build command to deploy your app to a production server. +The first step is to install a build tool like `vite`, `parcel`, or `rsbuild`. These build tools provide features to package and run source code, provide a development server for local development and a build command to deploy your app to a production server. ### Vite {/*vite*/} @@ -50,6 +50,16 @@ npm install --save-dev parcel Parcel supports fast refresh, JSX, TypeScript, Flow, and styling out of the box. See [Parcel's React recipe](https://parceljs.org/recipes/react/#getting-started) to get started. +### Rsbuild {/*rsbuild*/} + +[Rsbuild](https://rsbuild.dev/) is an Rspack-powered build tool that provides a seamless development experience for React applications. It comes with carefully tuned defaults and performance optimizations ready to use. + + +npx create-rsbuild --template react + + +Rsbuild includes built-in support for React features like fast refresh, JSX, TypeScript, and styling. See [Rsbuild's React guide](https://rsbuild.dev/guide/framework/react) to get started. + #### Metro for React Native {/*react-native*/} From 1923248a1ebdae4062a5290d8242fe2e94c0ec04 Mon Sep 17 00:00:00 2001 From: Zack Chapple Date: Mon, 17 Feb 2025 01:28:59 -0500 Subject: [PATCH 014/139] fix(docs): webpack branding states it should be lower case (#7617) * fix(docs): webpack branding states it should be lower case * chore: fix more occurrences --------- Co-authored-by: Strek --- .../06/15/react-labs-what-we-have-been-working-on-june-2022.md | 2 +- src/content/blog/2025/02/14/sunsetting-create-react-app.md | 2 +- src/content/learn/react-compiler.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md index 80fcb78e6..1aaa94ec1 100644 --- a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md +++ b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md @@ -27,7 +27,7 @@ We announced an [experimental demo of React Server Components](https://legacy.re In particular, we’re abandoning the idea of having forked I/O libraries (eg react-fetch), and instead adopting an async/await model for better compatibility. This doesn’t technically block RSC’s release because you can also use routers for data fetching. Another change is that we’re also moving away from the file extension approach in favor of [annotating boundaries](https://github.com/reactjs/rfcs/pull/189#issuecomment-1116482278). -We’re working together with Vercel and Shopify to unify bundler support for shared semantics in both Webpack and Vite. Before launch, we want to make sure that the semantics of RSCs are the same across the whole React ecosystem. This is the major blocker for reaching stable. +We’re working together with Vercel and Shopify to unify bundler support for shared semantics in both webpack and Vite. Before launch, we want to make sure that the semantics of RSCs are the same across the whole React ecosystem. This is the major blocker for reaching stable. ## Asset Loading {/*asset-loading*/} diff --git a/src/content/blog/2025/02/14/sunsetting-create-react-app.md b/src/content/blog/2025/02/14/sunsetting-create-react-app.md index 531d9c9f6..e61c7ead9 100644 --- a/src/content/blog/2025/02/14/sunsetting-create-react-app.md +++ b/src/content/blog/2025/02/14/sunsetting-create-react-app.md @@ -52,7 +52,7 @@ For existing apps, these guides will help you migrate to a client-only SPA: * [Next.js’ Create React App migration guide](https://nextjs.org/docs/app/building-your-application/upgrading/from-create-react-app) * [React Router’s framework adoption guide](https://reactrouter.com/upgrading/component-routes). -* [Expo Webpack to Expo Router migration guide](https://docs.expo.dev/router/migrate/from-expo-webpack/) +* [Expo webpack to Expo Router migration guide](https://docs.expo.dev/router/migrate/from-expo-webpack/) Create React App will continue working in maintenance mode, and we've published a new version of Create React App to work with React 19. diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 0ae499472..7c46673e7 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -311,7 +311,7 @@ export default defineConfig({ ### Webpack {/*usage-with-webpack*/} -A community Webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). ### Expo {/*usage-with-expo*/} From 09f39a07a1abacf92f9c92a6e36102ca2c3be2c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erasmo=20Hern=C3=A1ndez?= Date: Mon, 17 Feb 2025 14:26:18 -0300 Subject: [PATCH 015/139] fix: Dashboard component name in blogpost (#7621) --- src/content/blog/2025/02/14/sunsetting-create-react-app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/blog/2025/02/14/sunsetting-create-react-app.md b/src/content/blog/2025/02/14/sunsetting-create-react-app.md index e61c7ead9..cbc17fdcd 100644 --- a/src/content/blog/2025/02/14/sunsetting-create-react-app.md +++ b/src/content/blog/2025/02/14/sunsetting-create-react-app.md @@ -110,7 +110,7 @@ export default function App() { return (
{route === 'home' && } - {route === 'dashboard' && } + {route === 'dashboard' && }
) } From 604407a0da134d9f30ca3ba1e49bdf59ea8e098d Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 17 Feb 2025 17:54:29 -0500 Subject: [PATCH 016/139] Updates from feedback (#7624) * [Blog + Docs] Updates from feedback * Merge in changes from #7618 Co-authored-by: Mark Erikson * Say the words "Vite", "Parcel", and "Rsbuild" * Tweaks from feedback * re-apply #7615 * merge in #7622 Co-authored-by: elitalpa --------- Co-authored-by: Mark Erikson Co-authored-by: elitalpa --- .../2025/02/14/sunsetting-create-react-app.md | 37 +++-- src/content/blog/index.md | 2 +- .../learn/build-a-react-app-from-scratch.md | 143 ++++++++++++++++++ .../learn/building-a-react-framework.md | 137 ----------------- src/content/learn/creating-a-react-app.md | 27 ++-- src/content/learn/installation.md | 13 +- src/sidebarLearn.json | 4 +- vercel.json | 5 + 8 files changed, 194 insertions(+), 174 deletions(-) create mode 100644 src/content/learn/build-a-react-app-from-scratch.md delete mode 100644 src/content/learn/building-a-react-framework.md diff --git a/src/content/blog/2025/02/14/sunsetting-create-react-app.md b/src/content/blog/2025/02/14/sunsetting-create-react-app.md index cbc17fdcd..03d09c111 100644 --- a/src/content/blog/2025/02/14/sunsetting-create-react-app.md +++ b/src/content/blog/2025/02/14/sunsetting-create-react-app.md @@ -2,7 +2,7 @@ title: "Sunsetting Create React App" author: Matt Carroll and Ricky Hanlon date: 2025/02/14 -description: Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework. We’re also providing docs for when a framework isn’t a good fit for your project, or you prefer to start by building a framework. +description: Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch. --- February 14, 2025 by [Matt Carroll](https://twitter.com/mattcarrollcode) and [Ricky Hanlon](https://bsky.app/profile/ricky.fm) @@ -11,7 +11,9 @@ February 14, 2025 by [Matt Carroll](https://twitter.com/mattcarrollcode) and [Ri -Today, we’re deprecating [Create React App](https://create-react-app.dev/) for new apps, and encouraging existing apps to migrate to a [framework](/learn/creating-a-react-app). We’re also providing docs for when a framework isn’t a good fit for your project, or you prefer to start by [building a framework](/learn/building-a-react-framework). +Today, we’re deprecating [Create React App](https://create-react-app.dev/) for new apps, and encouraging existing apps to migrate to a [framework](#how-to-migrate-to-a-framework), or to [migrate to a build tool](how-to-migrate-to-a-build-tool) like Vite, Parcel, or RSBuild. + +We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by [building a React app from scratch](/learn/build-a-react-app-from-scratch). @@ -46,7 +48,10 @@ This error message will only be shown once per install. -We recommend [creating new React apps](/learn/creating-a-react-app) with a framework. All the frameworks we recommend support client-only SPAs, and can be deployed to a CDN or static hosting service without a server. +We've also added a deprecation notice to the Create React App [website](https://create-react-app.dev/) and GitHub [repo](https://github.com/facebook/create-react-app). Create React App will continue working in maintenance mode, and we've published a new version of Create React App to work with React 19. + +## How to Migrate to a Framework {/*how-to-migrate-to-a-framework*/} +We recommend [creating new React apps](/learn/creating-a-react-app) with a framework. All the frameworks we recommend support client-side rendering ([CSR](https://developer.mozilla.org/en-US/docs/Glossary/CSR)) and single-page apps ([SPA](https://developer.mozilla.org/en-US/docs/Glossary/SPA)), and can be deployed to a CDN or static hosting service without a server. For existing apps, these guides will help you migrate to a client-only SPA: @@ -54,27 +59,33 @@ For existing apps, these guides will help you migrate to a client-only SPA: * [React Router’s framework adoption guide](https://reactrouter.com/upgrading/component-routes). * [Expo webpack to Expo Router migration guide](https://docs.expo.dev/router/migrate/from-expo-webpack/) -Create React App will continue working in maintenance mode, and we've published a new version of Create React App to work with React 19. +## How to Migrate to a Build Tool {/*how-to-migrate-to-a-build-tool*/} If your app has unusual constraints, or you prefer to solve these problems by building your own framework, or you just want to learn how react works from scratch, you can roll your own custom setup with React using Vite, Parcel or Rsbuild. -To help users get started with Vite, Parcel or Rsbuild, we've published new docs for [Building a Framework](/learn/building-a-react-framework). Continue reading to learn more about the [limitations of Create React App](#limitations-of-create-react-app) and [why we recommend frameworks](#why-we-recommend-frameworks). +For existing apps, these guides will help you migrate to a build tool: - +* [Vite Create React App migration guide](https://www.robinwieruch.de/vite-create-react-app/) +* [Parcel Create React App migration guide](https://stackoverflow.com/a/49605484) +* [Rsbuild Create React App migration guide](https://rsbuild.dev/guide/migration/cra) + +To help get started with Vite, Parcel or Rsbuild, we've added new docs for [Building a React App from Scratch](/learn/build-a-react-app-from-scratch). -#### Do you recommend Vite? {/*do-you-recommend-vite*/} + -We provide several Vite-based recommendations. +#### Do I need a framework? {/*do-i-need-a-framework*/} -React Router v7 is a Vite based framework which allows you to use Vite's fast development server and build tooling with a framework that provides routing and data fetching. Just like the other frameworks we recommend, you can build a SPA with React Router v7. +Most apps would benefit from a framework, but there are valid cases to build a React app from scratch. A good rule of thumb is if your app needs routing, you would probably benefit from a framework. -We also recommend using Vite when [adding React to an existing project](/learn/add-react-to-an-existing-project), or [building a framework](/learn/building-a-react-framework). +Just like Svelte has Sveltekit, Vue has Nuxt, and Solid has SolidStart, [React recommends using a framework](#why-we-recommend-frameworks) that fully integrates routing into features like data-fetching and code-splitting out of the box. This avoids the pain of needing to write your own complex configurations and essentially build a framework yourself. -Just like Svelte has Sveltekit, Vue has Nuxt, and Solid has SolidStart, React recommends using a framework that integrates with build tools like Vite for new projects. +However, you can always [build a React app from scratch](/learn/build-a-react-app-from-scratch) using a build tool like Vite, Parcel, or Rsbuild. - + + +Continue reading to learn more about the [limitations of build tools](#limitations-of-create-react-app) and [why we recommend frameworks](#why-we-recommend-frameworks). -## Limitations of Create React App {/*limitations-of-create-react-app*/} +## Limitations of Build Tools {/*limitations-of-build-tools*/} Create React App and build tools like it make it easy to get started building a React app. After running `npx create-react-app my-app`, you get a fully configured React app with a development server, linting, and a production build. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 5cd4f35bd..5cd8304b1 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -14,7 +14,7 @@ You can also follow the [@react.dev](https://bsky.app/profiles/react.js) account -Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework. We’re also providing docs for when a framework isn’t a good fit for your project, or you prefer to start by building a framework. +Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/build-a-react-app-from-scratch.md b/src/content/learn/build-a-react-app-from-scratch.md new file mode 100644 index 000000000..50908d411 --- /dev/null +++ b/src/content/learn/build-a-react-app-from-scratch.md @@ -0,0 +1,143 @@ +--- +title: Build a React app from Scratch +--- + + + +If your app has constraints not well-served by existing frameworks, you prefer to build your own framework, or you just want to learn the basics of a React app, you can build a React app from scratch. + + + + + +#### Consider using a framework {/*consider-using-a-framework*/} + +Starting from scratch is an easy way to get started using React, but a major tradeoff to be aware of is that going this route is often the same as building your own adhoc framework. As your requirements evolve, you may need to solve more framework-like problems that our recommended frameworks already have well developed and supported solutions for. + +For example, if in the future your app needs support for server-side rendering (SSR), static site generation (SSG), and/or React Server Components (RSC), you will have to implement those on your own. Similarly, future React features that require integrating at the framework level will have to be implemented on your own if you want to use them. + +Our recommended frameworks also help you build better performing apps. For example, reducing or eliminating waterfalls from network requests makes for a better user experience. This might not be a high priority when you are building a toy project, but if your app gains users you may want to improve its performance. + +Going this route also makes it more difficult to get support, since the way you develop routing, data-fetching, and other features will be unique to your situation. You should only choose this option if you are comfortable tackling these problems on your own, or if you’re confident that you will never need these features. + +For a list of recommended frameworks, check out [Creating a React App](/learn/creating-a-react-app). + + + + +## Step 1: Install a build tool {/*step-1-install-a-build-tool*/} + +The first step is to install a build tool like `vite`, `parcel`, or `rsbuild`. These build tools provide features to package and run source code, provide a development server for local development and a build command to deploy your app to a production server. + +### Vite {/*vite*/} + +[Vite](https://vite.dev/) is a build tool that aims to provide a faster and leaner development experience for modern web projects. + + +{`npm create vite@latest my-app -- --template react`} + + +Vite is opinionated and comes with sensible defaults out of the box. Vite has a rich ecosystem of plugins to support fast refresh, JSX, Babel/SWC, and other common features. See Vite's [React plugin](https://vite.dev/plugins/#vitejs-plugin-react) or [React SWC plugin](https://vite.dev/plugins/#vitejs-plugin-react-swc) and [React SSR example project](https://vite.dev/guide/ssr.html#example-projects) to get started. + +Vite is already being used as a build tool in one of our [recommended frameworks](/learn/creating-a-react-app): [React Router](https://reactrouter.com/start/framework/installation). + +### Parcel {/*parcel*/} + +[Parcel](https://parceljs.org/) combines a great out-of-the-box development experience with a scalable architecture that can take your project from just getting started to massive production applications. + + +{`npm install --save-dev parcel`} + + +Parcel supports fast refresh, JSX, TypeScript, Flow, and styling out of the box. See [Parcel's React recipe](https://parceljs.org/recipes/react/#getting-started) to get started. + +### Rsbuild {/*rsbuild*/} + +[Rsbuild](https://rsbuild.dev/) is an Rspack-powered build tool that provides a seamless development experience for React applications. It comes with carefully tuned defaults and performance optimizations ready to use. + + +{`npx create-rsbuild --template react`} + + +Rsbuild includes built-in support for React features like fast refresh, JSX, TypeScript, and styling. See [Rsbuild's React guide](https://rsbuild.dev/guide/framework/react) to get started. + + + +#### Metro for React Native {/*react-native*/} + +If you'd you're starting from scratch with React Native you'll need to use [Metro](https://metrobundler.dev/), the JavaScript bundler for React Native. Metro supports bundling for platforms like iOS and Android, but lacks many features when compared to the tools here. We recommend starting with Vite, Parcel, or Rsbuild unless your project requires React Native support. + + + +### Step 2: Build Common Application Patterns {/*step-2-build-common-application-patterns*/} + +The build tools listed above start off with a client-only, single-page app (SPA), but don't include any further solutions for common functionality like routing, data fetching, or styling. + +The React ecosystem includes many tools for these problems. We've listed a few that are widely used as a starting point, but feel free to choose other tools if those work better for you. + +#### Routing {/*routing*/} + +Routing determines what content or pages to display when a user visits a particular URL. You need to set up a router to map URLs to different parts of your app. You'll also need to handle nested routes, route parameters, and query parameters. Routers can be configured within your code, or defined based on your component folder and file structures. + +Routers are a core part of modern applications, and are usually integrated with data fetching (including prefetching data for a whole page for faster loading), code splitting (to minimize client bundle sizes), and page rendering approaches (to decide how each page gets generated). + +We suggest using: + +- [React Router](https://reactrouter.com/start/framework/custom) +- [Tanstack Router](https://tanstack.com/router/latest) + + +#### Data Fetching {/*data-fetching*/} + +Fetching data from a server or other data source is a key part of most applications. Doing this properly requires handling loading states, error states, and caching the fetched data, which can be complex. + +Purpose-built data fetching libraries do the hard work of fetching and caching the data for you, letting you focus on what data your app needs and how to display it. These libraries are typically used directly in your components, but can also be integrated into routing loaders for faster pre-fetching and better performance, and in server rendering as well. + +Note that fetching data directly in components can lead to slower loading times due to network request waterfalls, so we recommend prefetching data in router loaders or on the server as much as possible! This allows a page's data to be fetched all at once as the page is being displayed. + +If you're fetching data from most backends or REST-style APIs, we suggest using: + +- [React Query](https://react-query.tanstack.com/) +- [SWR](https://swr.vercel.app/) +- [RTK Query](https://redux-toolkit.js.org/rtk-query/overview) + +If you're fetching data from a GraphQL API, we suggest using: + +- [Apollo](https://www.apollographql.com/docs/react) +- [Relay](https://relay.dev/) + + +### Code-splitting {/*code-splitting*/} + +Code-splitting is the process of breaking your app into smaller bundles that can be loaded on demand. An app's code size increases with every new feature and additional dependency. Apps can become slow to load because all of the code for the entire app needs to be sent before it can be used. Caching, reducing features/dependencies, and moving some code to run on the server can help mitigate slow loading but are incomplete solutions that can sacrifice functionality if overused. + +Similarly, if you rely on the apps using your framework to split the code, you might encounter situations where loading becomes slower than if no code splitting were happening at all. For example, [lazily loading](/reference/react/lazy) a chart delays sending the code needed to render the chart, splitting the chart code from the rest of the app. [Parcel supports code splitting with React.lazy](https://parceljs.org/recipes/react/#code-splitting). However, if the chart loads its data *after* it has been initially rendered you are now waiting twice. This is a waterfall: rather than fetching the data for the chart and sending the code to render it simultaneously, you must wait for each step to complete one after the other. + +Splitting code by route, when integrated with bundling and data fetching, can reduce the initial load time of your app and the time it takes for the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/articles/lcp)). + +For code-splitting instructions, see your build tool docs: +- [Vite build optimizations](https://v3.vitejs.dev/guide/features.html#build-optimizations) +- [Parcel code splitting](https://parceljs.org/features/code-splitting/) +- [Rsbuild code splitting](https://rsbuild.dev/guide/optimization/code-splitting) + +### Improving Application Performance {/*improving-application-performance*/} + +Since the build tool you select only support single page apps (SPAs) you'll need to implement other [rendering patterns](https://www.patterns.dev/vanilla/rendering-patterns) like server-side rendering (SSR), static site generation (SSG), and/or React Server Components (RSC). Even if you don't need these features at first, in the future there may be some routes that would benefit SSR, SSG or RSC. + +* **Single-page apps (SPA)** load a single HTML page and dynamically updates the page as the user interacts with the app. SPAs are easier to get started with, but they can have slower initial load times. SPAs are the default architecture for most build tools. + +* **Streaming Server-side rendering (SSR)** renders a page on the server and sends the fully rendered page to the client. SSR can improve performance, but it can be more complex to set up and maintain than a single-page app. With the addition of streaming, SSR can be very complex to set up and maintain. See [Vite's SSR guide]( https://vite.dev/guide/ssr). + +* **Static site generation (SSG)** generates static HTML files for your app at build time. SSG can improve performance, but it can be more complex to set up and maintain than server-side rendering. + +* **React Server Components (RSC)** lets you mix build-time, server-only, and interactive components in a single React tree. RSC can improve performance, but it currently requires deep expertise to set up and maintain. See [Parcel's RSC examples](https://github.com/parcel-bundler/rsc-examples). + +Your rendering strategies need to integrate with your router so apps built with your framework can choose the rendering strategy on a per-route level. This will enable different rendering strategies without having to rewrite your whole app. For example, the landing page for your app might benefit from being statically generated (SSG), while a page with a content feed might perform best with server-side rendering. + +Using the right rendering strategy for the right routes can decrease the time it takes for the first byte of content to be loaded ([Time to First Byte](https://web.dev/articles/ttfb)), the first piece of content to render ([First Contentful Paint](https://web.dev/articles/fcp)), and the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/articles/lcp)). + +### And more... {/*and-more*/} + +These are just a few examples of the features a new app will need to consider when building from scratch. Many limitations you'll hit can be difficult to solve as each problem is interconnected with the others and can require deep expertise in problem areas you may not be familiar with. + +If you don't want to solve these problems on your own, you can [get started with a framework](/learn/creating-a-react-app) that provides these features out of the box. diff --git a/src/content/learn/building-a-react-framework.md b/src/content/learn/building-a-react-framework.md deleted file mode 100644 index 50e34ff65..000000000 --- a/src/content/learn/building-a-react-framework.md +++ /dev/null @@ -1,137 +0,0 @@ ---- -title: Building a React Framework ---- - - - -If your app has constraints not well-served by existing frameworks, or you prefer to solve these problems yourself, you can build your own framework. - - - - - -### Consider using an existing framework {/*you-should-probably-use-a-framework*/} - -Building a framework is complex and requires extensive expertise across various domains. This complexity is not limited to React — it is a widespread challenge encountered by all UI libraries. Using an existing framework can save significant time and effort by allowing you to focus on building your application. Existing frameworks have tested, robust features and community support. - -For a list of recommended frameworks, check out [Creating a React App](/learn/creating-a-react-app). - - - -Building a framework is a large undertaking that often requires expertise in many different areas. Understanding your goals and requirements before starting to build your own framework can help guide your development process and save a considerable amount of time. - -For example, if you need to build a framework that integrates with a specific system or infrastructure, it's important to understand the features and limitations of those systems. Understanding your constraints can help guide your framework development process. - -If you are building your own framework to learn, using popular tools like Vite and React Router can be a good starting point and let you focus on how to combine different tools to build a framework. - -## Step 1: Install a build tool {/*step-1-install-a-build-tool*/} - -The first step is to install a build tool like `vite`, `parcel`, or `rsbuild`. These build tools provide features to package and run source code, provide a development server for local development and a build command to deploy your app to a production server. - -### Vite {/*vite*/} - -[Vite](https://vite.dev/) is a build tool that aims to provide a faster and leaner development experience for modern web projects. - - -npm create vite@latest my-app -- --template react - - -Vite is opinionated and comes with sensible defaults out of the box. Vite has a rich ecosystem of plugins to support fast refresh, JSX, Babel/SWC, and other common features. See Vite's [React plugin](https://vite.dev/plugins/#vitejs-plugin-react) or [React SWC plugin](https://vite.dev/plugins/#vitejs-plugin-react-swc) and [React SSR example project](https://vite.dev/guide/ssr.html#example-projects) to get started. - -Vite is already being used as a build tool in one of our [recommended frameworks](/learn/creating-a-react-app): [React Router](https://reactrouter.com/start/framework/installation). - -### Parcel {/*parcel*/} - -[Parcel](https://parceljs.org/) combines a great out-of-the-box development experience with a scalable architecture that can take your project from just getting started to massive production applications. - - -npm install --save-dev parcel - - -Parcel supports fast refresh, JSX, TypeScript, Flow, and styling out of the box. See [Parcel's React recipe](https://parceljs.org/recipes/react/#getting-started) to get started. - -### Rsbuild {/*rsbuild*/} - -[Rsbuild](https://rsbuild.dev/) is an Rspack-powered build tool that provides a seamless development experience for React applications. It comes with carefully tuned defaults and performance optimizations ready to use. - - -npx create-rsbuild --template react - - -Rsbuild includes built-in support for React features like fast refresh, JSX, TypeScript, and styling. See [Rsbuild's React guide](https://rsbuild.dev/guide/framework/react) to get started. - - - -#### Metro for React Native {/*react-native*/} - -If you'd like your framework to support React Native you'll need to use [Metro](https://metrobundler.dev/), the JavaScript bundler for React Native. Metro supports bundling for platforms like iOS and Android, but lacks many features when compared to Vite or Parcel. We recommend starting with Vite or Parcel unless your project requires React Native support. - - - -## Step 2: Build your framework {/*step-2-build-your-framework*/} - -The build tool you select starts with a client-only, single-page app (SPA). While SPAs can be a good place to start, many SPAs will encounter problems as they grow. Frameworks can provide the scaffolding to solve these problems. Most frameworks will implement routing, code-splitting, different rendering strategies, and data-fetching. These features are interconnected. For example, if you use a router that only works on the client it could prevent you from implementing server-side rendering. The best frameworks provide a cohesive, consistent experience across these features for developers and users. - -### Routing {/*routing*/} - -Routing determines what to display when a user visits a particular URL. You need to set up a router to map URLs to different parts of your app. You'll also need to handle nested routes, route parameters, and query parameters. Most modern routers use file-based routing. Routing can be integrated with other features like: - -* **Rendering strategies** to enable different rendering strategies on different routes, so you can introduce new strategies without having to rewrite your whole app. This can decrease the time it takes for the first byte of content to be loaded ([Time to First Byte](https://web.dev/articles/ttfb)), the first piece of content to be rendered ([First Contentful Paint](https://web.dev/articles/fcp)), and the largest visible content of the app to be rendered ([Largest Contentful Paint](https://web.dev/articles/lcp)). -* **Data fetching** to enable data fetching before the page loads on a route. This can prevent layout shifts ([Cumulative Layout Shift](https://web.dev/articles/cls)) and decrease the time it takes for the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/articles/lcp)) -* **Code splitting** to reduce the JavaScript bundle size sent to the client and improve performance on underpowered devices. This can reduce the time it takes for the browser to respond to a user interaction ([First Input Delay](https://web.dev/articles/fid)) and the largest visible content of the app to be rendered ([Largest Contentful Paint](https://web.dev/articles/lcp)). - -If you're not sure how to get started with routing, we recommend using [React Router](https://reactrouter.com/start/framework/custom) or [Tanstack Router](https://tanstack.com/router/latest). - -### Data-fetching {/*data-fetching*/} - -Data-fetching is the process of fetching data from a server or other data source. You need to set up or create a data-fetching library to handle data retrieval from your server and manage the state of that data. You'll also need to handle loading states, error states, and caching data. Data fetching can be integrated with features like: - -* **Routing** to enable data fetching to take place before page loads. This can improve how quickly a page loads and becomes visible to users ([Largest Contentful Paint](https://web.dev/lcp)) and reduce time it takes for your app to be interactive ([Time to Interactive](https://web.dev/tti)). -* **Rendering strategies** to prerender fetched data before it is sent to the client. This can reduce the time it takes for the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/lcp)). - -Integrating routing and data fetching is particularly important to prevent network waterfalls. In a SPA, if you fetch data during a component's initial render, the first data fetch is delayed until all code has loaded and components have finished rendering. This is commonly known as a waterfall: instead of fetching data at the same time as your code is loading, you need to first wait for your code to load before fetching data. To address these waterfalls, your app needs to fetch the data for each route in parallel with sending code to the browser. - -Popular data fetching libraries that you can use as a part of your framework include [React Query](https://react-query.tanstack.com/), [SWR](https://swr.vercel.app/), [Apollo](https://www.apollographql.com/docs/react), and [Relay](https://relay.dev/). - -### Rendering strategies {/*rendering-strategies*/} - -Since the build tool you select only support single page apps (SPAs) you'll need to implement other [rendering patterns](https://www.patterns.dev/vanilla/rendering-patterns) like server-side rendering (SSR), static site generation (SSG), and/or React Server Components (RSC). Even if you don't need these features at first, in the future there may be some routes that would benefit SSR, SSG or RSC. - -* **Single-page apps (SPA)** load a single HTML page and dynamically updates the page as the user interacts with the app. SPAs are fast and responsive, but they can have slower initial load times. SPAs are the default architecture for most build tools. - -* **Streaming Server-side rendering (SSR)** renders a page on the server and sends the fully rendered page to the client. SSR can improve performance, but it can be more complex to set up and maintain than a single-page app. With the addition of streaming, SSR can be very complex to set up and maintain. See [Vite's SSR guide]( https://vite.dev/guide/ssr). - -* **Static site generation (SSG)** generates static HTML files for your app at build time. SSG can improve performance, but it can be more complex to set up and maintain than server-side rendering. - -* **React Server Components (RSC)** lets you mix build-time, server-only, and interactive components in a single React tree. RSC can improve performance, but it currently requires deep expertise to set up and maintain. See [Parcel's RSC examples](https://github.com/parcel-bundler/rsc-examples). - -Your rendering strategies need to integrate with your router so apps built with your framework can choose the rendering strategy on a per-route level. This will enable different rendering strategies without having to rewrite your whole app. For example, the landing page for your app might benefit from being statically generated (SSG), while a page with a content feed might perform best with server-side rendering. Using the right rendering strategy for the right routes can decrease the time it takes for the first byte of content to be loaded ([Time to First Byte](https://web.dev/articles/ttfb)), the first piece of content to render ([First Contentful Paint](https://web.dev/articles/fcp)), and the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/articles/lcp)). - -### Code-splitting {/*code-splitting*/} - -Code-splitting is the process of breaking your app into smaller bundles that can be loaded on demand. An app's code size increases with every new feature and additional dependency. Apps can become slow to load because all of the code for the entire app needs to be sent before it can be used. Caching, reducing features/dependencies, and moving some code to run on the server can help mitigate slow loading but are incomplete solutions that can sacrifice functionality if overused. - -Similarly, if you rely on the apps using your framework to split the code, you might encounter situations where loading becomes slower than if no code splitting were happening at all. For example, [lazily loading](/reference/react/lazy) a chart delays sending the code needed to render the chart, splitting the chart code from the rest of the app. [Parcel supports code splitting with React.lazy](https://parceljs.org/recipes/react/#code-splitting). However, if the chart loads its data *after* it has been initially rendered you are now waiting twice. This is a waterfall: rather than fetching the data for the chart and sending the code to render it simultaneously, you must wait for each step to complete one after the other. - -Splitting code by route, when integrated with bundling and data fetching, can reduce the initial load time of your app and the time it takes for the largest visible content of the app to render ([Largest Contentful Paint](https://web.dev/articles/lcp)). - -### And more... {/*and-more*/} - -These are just a few examples of the features a framework will need to consider. - -There are many other problems that users need to solve like: - -- Accessibility -- Asset loading -- Authentication -- Error handling -- Mutating data -- Navigations -- Nested routes -- Optimistic updates -- Caching -- Progressive enhancement -- Static site generation -- Server-side rendering - -Many of these problems individually can be difficult as each problem is interconnected with the others and can require deep expertise in problem areas you may not be familiar with. If you don't want to solve these problems on your own, you can [get started with a framework](/learn/creating-a-react-app) that provides these features out of the box. diff --git a/src/content/learn/creating-a-react-app.md b/src/content/learn/creating-a-react-app.md index cf7359e45..fc5019ece 100644 --- a/src/content/learn/creating-a-react-app.md +++ b/src/content/learn/creating-a-react-app.md @@ -8,15 +8,19 @@ If you want to build a new app or website with React, we recommend starting with -## Recommended React frameworks {/*bleeding-edge-react-frameworks*/} +If your app has constraints not well-served by existing frameworks, you prefer to build your own framework, or you just want to learn the basics of a React app, you can [build a React app from scratch](/learn/build-a-react-app-from-scratch). + +## Full-stack frameworks {/*full-stack-frameworks*/} These recommended frameworks support all the features you need to deploy and scale your app in production. They have integrated the latest React features and take advantage of React’s architecture. -#### React frameworks do not require a server. {/*react-frameworks-do-not-require-a-server*/} +#### Full-stack frameworks do not require a server. {/*react-frameworks-do-not-require-a-server*/} + +All the frameworks on this page support client-side rendering ([CSR](https://developer.mozilla.org/en-US/docs/Glossary/CSR)), single-page apps ([SPA](https://developer.mozilla.org/en-US/docs/Glossary/SPA)), and static-site generation ([SSG](https://developer.mozilla.org/en-US/docs/Glossary/SSG)). These apps can be deployed to a [CDN](https://developer.mozilla.org/en-US/docs/Glossary/CDN) or static hosting service without a server. Additionally, these frameworks allow you to add server-side rendering on a per-route basis, when it makes sense for your use case. -All the frameworks on this page can create single-page apps. Single-page apps can be deployed to a [CDN](https://developer.mozilla.org/en-US/docs/Glossary/CDN) or static hosting service and do not need a server. If you would like to enable features that require a server (like server side rendering), you can opt-in on individual routes without rewriting your app. +This allows you to start with a client-only app, and if your needs change later, you can opt-in to using server features on individual routes without rewriting your app. See your framework's documentation for configuring the rendering strategy. @@ -55,7 +59,7 @@ If you're new to Expo, check out the [Expo tutorial](https://docs.expo.dev/tutor Expo is maintained by [Expo (the company)](https://expo.dev/about). Building apps with Expo is free, and you can submit them to the Google and Apple app stores without restrictions. Expo additionally provides opt-in paid cloud services. -## Other options {/*other-options*/} +## Other frameworks {/*other-frameworks*/} There are other up-and-coming frameworks that are working towards our full stack React vision: @@ -96,20 +100,13 @@ Server Components and Suspense are React features rather than Next.js features. - - +## Start From Scratch {/*start-from-scratch*/} -#### Do you recommend Vite? {/*do-you-recommend-vite*/} +If your app has constraints not well-served by existing frameworks, you prefer to build your own framework, or you just want to learn the basics of a React app, there are other options available for starting a React project from scratch. -We provide several Vite-based recommendations. +Starting from scratch gives you more flexibility, but does require that you make choices on which tools to use for routing, data fetching, and other common usage patterns. It's a lot like building your own framework, instead of using a framework that already exists. The [frameworks we recommend](#recommended-react-frameworks) have built-in solutions for these problems. -React Router v7 is a Vite based framework which allows you to use Vite's fast development server and build tooling with a framework that provides routing and data fetching. Just like the other frameworks we recommend, you can build a SPA with React Router v7. - -We also recommend using Vite when [adding React to an existing project](/learn/add-react-to-an-existing-project), or [building a framework](/learn/building-a-react-framework). - -Just like Svelte has Sveltekit, Vue has Nuxt, and Solid has SolidStart, React recommends using a framework that integrates with build tools like Vite for new projects. - - +If you want to build your own solutions, see our guide to [build a React app from Scratch](/learn/build-a-react-app-from-scratch) for instructions on how to set up a new React project starting with a built tool like [Vite](https://vite.dev/), [Parcel](https://parceljs.org/), or [RSbuild](https://rsbuild.dev/). ----- diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index f9a5b10fd..ab538e5bb 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -36,21 +36,22 @@ To try React locally on your computer, [download this HTML page.](https://gist.g If you want to start a new React app, you can [create a React app](/learn/creating-a-react-app) using a recommended framework. -## Build a React Framework {/*build-a-react-framework*/} +## Build a React App from Scratch {/*build-a-react-app-from-scratch*/} -If a framework is not a good fit for your project, or you prefer to start by building your own framework, you can [build your own React framework](/learn/building-a-react-framework). +If a framework is not a good fit for your project, you prefer to build your own framework, or you just want to learn the basics of a React app you can [build a React app from scratch](/learn/build-a-react-app-from-scratch). ## Add React to an existing project {/*add-react-to-an-existing-project*/} If want to try using React in your existing app or a website, you can [add React to an existing project.](/learn/add-react-to-an-existing-project) -## Deprecated Options {/*deprecated-options*/} -### Create React App (Deprecated) {/*create-react-app-deprecated*/} + -Create React App is a deprecated tool, previously recommended for creating new React apps. If you want to start a new React app, you can [create a React app](/learn/creating-a-react-app) using a recommended framework. +#### Should I use Create React App? {/*should-i-use-create-react-app*/} -For more information, see [Sunsetting Create React App](/blog/2025/02/14/sunsetting-create-react-app). +No. Create React App has been deprecated. For more information, see [Sunsetting Create React App](/blog/2025/02/14/sunsetting-create-react-app). + + ## Next steps {/*next-steps*/} diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 7471eb20c..c83fdb189 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -29,8 +29,8 @@ "path": "/learn/creating-a-react-app" }, { - "title": "Building a React Framework", - "path": "/learn/building-a-react-framework" + "title": "Build a React App from Scratch", + "path": "/learn/build-a-react-app-from-scratch" }, { "title": "Add React to an Existing Project", diff --git a/vercel.json b/vercel.json index fdd63f5bb..1a55e2063 100644 --- a/vercel.json +++ b/vercel.json @@ -234,6 +234,11 @@ "destination": "/learn/creating-a-react-app", "permanent": true }, + { + "source": "/learn/building-a-react-framework", + "destination": "/learn/build-a-react-app-from-scratch", + "permanent": true + }, { "source": "/blog/2024/04/25/react-19", "destination": "/blog/2024/12/05/react-19", From c18b2759fc5d3d10c2bf9a8fb87ba5cdd5cc24c0 Mon Sep 17 00:00:00 2001 From: alinkedd Date: Tue, 18 Feb 2025 00:11:46 +0100 Subject: [PATCH 017/139] Resolve merge conflicts --- src/content/learn/installation.md | 31 +---- .../learn/start-a-new-react-project.md | 130 ------------------ src/sidebarLearn.json | 5 - 3 files changed, 2 insertions(+), 164 deletions(-) delete mode 100644 src/content/learn/start-a-new-react-project.md diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 1cf5bb00f..30690ef92 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -8,20 +8,7 @@ title: Встановлення -<<<<<<< HEAD - - -* [Як почати новий React-проєкт](/learn/start-a-new-react-project) -* [Як інтегрувати React у наявний проєкт](/learn/add-react-to-an-existing-project) -* [Як налаштувати редактор коду](/learn/editor-setup) -* [Як встановити інструменти React розробника](/learn/react-developer-tools) - - - ## Спробувати React {/*try-react*/} -======= -## Try React {/*try-react*/} ->>>>>>> 49284218b1f5c94f930f8a9b305040dbe7d3dd48 Не потрібно нічого встановлювати, щоб погратися з React. Спробуйте відредагувати код у цій пісочниці! @@ -43,32 +30,19 @@ export default function App() { Більшість сторінок у документації React містять схожі пісочниці. Водночас існує багато інших онлайн-пісочниць з підтримкою React, наприклад: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) або [CodePen.](https://codepen.io/pen?template=QWYVwWN) -<<<<<<< HEAD -### Спробувати React локально {/*try-react-locally*/} - Щоб спробувати React локально на вашому комп'ютері, [завантажте цю HTML-сторінку.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Відкрийте її у редакторі та браузері! -## Почати новий React-проєкт {/*start-a-new-react-project*/} - -Якщо ви хочете створити застосунок або вебсайт за допомогою React, [почніть новий React-проєкт.](/learn/start-a-new-react-project) -======= -To try React locally on your computer, [download this HTML page.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Open it in your editor and in your browser! - -## Creating a React App {/*creating-a-react-app*/} +## Початок React-проєкту {/*creating-a-react-app*/} -If you want to start a new React app, you can [create a React app](/learn/creating-a-react-app) using a recommended framework. +Якщо ви хочете створити застосунок за допомогою React, [почніть React-проєкт](/learn/creating-a-react-app), використовуючи один із рекомендованих фреймворків. ## Build a React Framework {/*build-a-react-framework*/} If a framework is not a good fit for your project, or you prefer to start by building your own framework, you can [build your own React framework](/learn/building-a-react-framework). ->>>>>>> 49284218b1f5c94f930f8a9b305040dbe7d3dd48 ## Інтегрувати React у наявний проєкт {/*add-react-to-an-existing-project*/} -<<<<<<< HEAD Якщо ви хочете використати React у власному застосунку або вебсайті, [інтегруйте React у наявний проєкт.](/learn/add-react-to-an-existing-project) -======= -If want to try using React in your existing app or a website, you can [add React to an existing project.](/learn/add-react-to-an-existing-project) ## Deprecated Options {/*deprecated-options*/} @@ -77,7 +51,6 @@ If want to try using React in your existing app or a website, you can [add React Create React App is a deprecated tool, previously recommended for creating new React apps. If you want to start a new React app, you can [create a React app](/learn/creating-a-react-app) using a recommended framework. For more information, see [Sunsetting Create React App](/blog/2025/02/14/sunsetting-create-react-app). ->>>>>>> 49284218b1f5c94f930f8a9b305040dbe7d3dd48 ## Подальші кроки {/*next-steps*/} diff --git a/src/content/learn/start-a-new-react-project.md b/src/content/learn/start-a-new-react-project.md deleted file mode 100644 index be3510ceb..000000000 --- a/src/content/learn/start-a-new-react-project.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Початок нового React-проєкту ---- - - - -Якщо ви вирішили розробити новий застосунок або новий вебсайт цілком за допомогою React, ми радимо вибрати один із популярних у нашій спільноті React-фреймворків. - - - - -Ви можете використовувати React без фреймворку, проте ми з'ясували, що більшість застосунків і сайтів, зрештою, створюють рішення для поширених проблем, наприклад: розбиття коду, маршрутизації, отримання даних і генерування HTML. Ці проблеми — спільні для всіх бібліотек UI, а не лише для React. - -Вибравши фреймворк, можна швидко почати роботу з React і уникнути, по суті, розробки власного фреймворку пізніше. - - - -#### Чи можна використовувати React без фреймворку? {/*can-i-use-react-without-a-framework*/} - -Звісно можна використовувати React без фреймворку — так само, як можна [використовувати React для частини сторінки.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) **Однак якщо ви розробляєте новий застосунок або сайт повністю за допомогою React, ми радимо скористатися фреймворком.** - -І ось чому. - -Навіть якщо вам спершу не потрібні маршрутизація чи отримання даних, то існує ймовірність того, що ви захочете додати для цих функцій кілька бібліотек. Поки ваш бандл JavaScript розростатиметься з кожною новою функцією, ви будете розбиратися, як розбити код для кожного окремого маршруту. Поки ваші потреби з отримання даних ускладнюватимуться, ймовірно, ви зустрінете серверно-клієнтські мережеві водоспади, що зроблять ваш застосунок дуже повільним. Коли серед ваших користувачів з'явиться більше осіб із поганим з'єднанням і бюджетними пристроями, вам може знадобитися генерація HTML із компонентів, щоб показувати вміст раніше — або з боку сервера, або під час збирання сайту. Зміна налаштувань для виконання частини коду на сервері чи під час збирання може стати завданням із зірочкою. - -**Ці проблеми не стосуються лише React. Це саме те, через що у Svelte є SvelteKit, у Vue є Nuxt і так далі.** Щоб вирішити ці проблеми самотужки, доведеться інтегрувати свій бандлер зі своїм маршрутизатором і зі своєю бібліотекою отримання даних. Неважко змусити працювати вкупі якийсь базовий варіант, проте є чимало тонкощів у створенні застосунку, який, зростаючи з часом, буде все ще швидко завантажуватися. Захочеться надсилати до браузера якнайменшу кількість коду застосунку, але робити це за один захід клієнт-сервер і паралельно до завантаження всіх необхідних на сторінці даних. Ймовірно, захочеться, щоб сторінка була інтерактивною навіть до виконання коду JavaScript, щоб підтримувати поступове покращення (progressive enhancement). Може захотітися генерувати теку повністю статичних файлів HTML для рекламних сторінок, які можуть викладатися будь-де і працювати навіть із вимкненим JavaScript. Розробка такого функціоналу вимагає суттєвих зусиль. - -**Наведені на цій сторінці фреймворки React вже вирішують такі проблеми, не потребуючи додаткових зусиль з вашого боку.** Вони дають змогу почати з малого, аби потім масштабувати застосунок відповідно до потреб. Кожний React-фреймворк має свою спільноту, тож шукати відповіді на питання та оновлювати інструменти розробки буде легше. Також фреймворки задають структуру коду, допомагаючи вам та іншим зберігати той самий контекст і користуватися тими ж навичками в різних проєктах. І навпаки: із саморобними налаштуваннями легше застрягнути у версіях залежностей, що більше не підтримуються, і, по суті, доведеться створювати власний фреймворк — але без власної спільноти та інструкцій з оновлення (і якщо він буде схожим на те, що колись писали ми, то цей ваш фреймворк буде написаний абияк). - -Якщо ваш застосунок містить незвичні обмеження, які не спрацюють із переліченими нижче фреймворками, або ви хочете розв'язувати ці проблеми самотужки, то можете розгорнути власну конфігурацію з React. Візьміть `react` і `react-dom` із npm, налаштуйте власний процес збирання з використанням бандлеру, як-от [Vite](https://vite.dev/) або [Parcel](https://parceljs.org/), і додавайте інші інструменти за необхідності для маршрутизації, статичної генерації, серверного рендерингу чи чогось іще. - - - -## Готові до впровадження фреймворки React {/*production-grade-react-frameworks*/} - -Ці фреймворки підтримують усі функції, що знадобляться для розгортання та масштабування застосунку в публічному середовищі (in production), та прямують до підтримки нашого [бачення архітектури повного стеку](#which-features-make-up-the-react-teams-full-stack-architecture-vision). Усі фреймворки, які ми радимо, є відкритим програмним забезпеченням з активною спільнотою для підтримки та можуть бути розгорнуті на власних серверах чи сторонніх хостингах. Якщо ви автор фреймворку та зацікавлені у потраплянні до цього списку, [будь ласка, повідомте нас](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+). - -### Next.js {/*nextjs-pages-router*/} - -**[Page Router від Next.js](https://nextjs.org/) — це фреймворк React повного стеку.** Він багатоцільовий та дає змогу розробляти застосунки React будь-якого розміру — від здебільшого статичних блогів до складних динамічних програм. Щоб створити новий проєкт Next.js, запустіть у терміналі: - - -npx create-next-app@latest - - -Якщо Next.js — це для вас дещо нове, то погляньте на [курс вивчення Next.js.](https://nextjs.org/learn) - -Next.js підтримується командою [Vercel](https://vercel.com/). [Розгорнути застосунок Next.js](https://nextjs.org/docs/app/building-your-application/deploying) можна на будь-якому Node.js- або безсерверному хостингу, а також на власному сервері. Також Next.js підтримує [статичне експортування](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports), якому не потрібен сервер. - -### Remix {/*remix*/} - -**[Remix](https://remix.run/) — це фреймворк React повного стеку з вкладеною маршрутизацією.** Він дає змогу розбивати застосунок на вкладені одна в одну частини, які можуть паралельно завантажувати дані та оновлювати їх, реагуючи на дії користувача. Щоб створити новий проєкт Remix, запустіть: - - -npx create-remix - - -Якщо Remix — це для вас щось нове, перегляньте його [посібник зі створення блогу](https://remix.run/docs/en/main/tutorials/blog) (коротко) та [посібник зі створення застосунку](https://remix.run/docs/en/main/tutorials/jokes) (довго). - -Remix підтримується командою [Shopify](https://www.shopify.com/). Для створення проєкту Remix необхідно [вибрати свій варіант шаблону для розгортання](https://remix.run/docs/en/main/guides/deployment). Застосунок Remix можна розгорнути на будь-якому хостингу, що підтримує Node.js або є безсерверним, за допомогою готового чи власного [адаптера](https://remix.run/docs/en/main/other-api/adapter). - -### Gatsby {/*gatsby*/} - -**[Gatsby](https://www.gatsbyjs.com/) — це фреймворк React для швидких вебсайтів із системою керування вмістом.** Його багата екосистема плагінів і шар даних на основі GraphQL спрощують інтеграцію вмісту, API і сторонніх служб в один вебсайт. Щоб створити новий проєкт Gatsby, запустіть: - - -npx create-gatsby - - -Якщо Gatsby — це для вас щось нове, перегляньте [підручник Gatsby.](https://www.gatsbyjs.com/docs/tutorial/) - -Gatsby підтримується командою [Netlify](https://www.netlify.com/). [Повністю статичний сайт Gatsby можна розгорнути](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting) на будь-якому статичному хостингу. За бажання скористатися суто серверними функціями фреймворку слід перевірити, що хостинг підтримує ці можливості для Gatsby. - -### Expo (для нативних застосунків) {/*expo*/} - -**[Expo](https://expo.dev/) — це фреймворк React, що дає змогу створювати універсальні застосунки для Android, iOS і вебу з по-справжньому нативним UI.** Він пропонує набір інструментів для [React Native](https://reactnative.dev/), завдяки якому цими нативними частинами легше користуватися. Щоб створити новий проєкт Expo, запустіть: - - -npx create-expo-app - - -Якщо Expo — це для вас щось нове, перегляньте [підручник Expo](https://docs.expo.dev/tutorial/introduction/). - -Expo підтримується [компанією Expo](https://expo.dev/about). Розробляти застосунки за допомогою Expo можна безкоштовно, і їх можна подавати до каталогів застосунків Google і Apple без жодних обмежень. На додачу Expo пропонує необов'язкові платні хмарні послуги. - -## Передові фреймворки React {/*bleeding-edge-react-frameworks*/} - -Під час досліджень заради подальшого покращення React ми усвідомили, що тісніша інтеграція React із фреймворками (а саме з маршрутизацією, згортанням і серверними технологіями) — це наша найбільша нагода допомогти користувачам React створювати кращі застосунки. Команда Next.js погодилася співпрацювати з нами щодо досліджень, розробки, інтегрування та тестування незалежних від фреймворків функцій React штибу [серверних компонентів React.](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) - -З кожним днем ці функції наближаються до стану готовності до впровадження (production-ready), і ми обговорюємо їх інтеграцію з іншими розробниками бандлерів і фреймворків. Сподіваємося, що за рік чи два усі фреймворки, перелічені на цій сторінці, матимуть підтримку цих функцій. (Якщо ви автор фреймворку та зацікавлені у співпраці щодо експериментів із цими функціями, будь ласка, повідомте нас!) - -### Next.js (App Router) {/*nextjs-app-router*/} - -**[App Router від Next.js](https://nextjs.org/docs) — це переробка API Next.js, що прагне втілити бачення повностекової архітектури команди React.** Вона дає змогу отримувати дані в асинхронних компонентах, що запускаються на сервері чи навіть під час збирання. - -Next.js підтримується командою [Vercel](https://vercel.com/). [Застосунок Next.js можна розгорнути](https://nextjs.org/docs/app/building-your-application/deploying) на будь-якому Node.js- або безсерверному хостингу, а також на власному сервері. Також Next.js підтримує [статичне експортування](https://nextjs.org/docs/app/building-your-application/deploying/static-exports), якому не потрібен сервер. - - - -#### З яких функцій складається бачення архітектури повного стеку від команди React? {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} - -Бандлер App Router від Next.js повністю реалізує офіційну [специфікацію серверних компонентів React](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md). Це дає змогу поєднувати компоненти, що запускаються під час збирання, ті, що працюють суто на сервері, та інтерактивні компоненти в єдине дерево React. - -Наприклад, можна написати суто серверний компонент React як `async` функцію, що зчитує дані з бази даних або з файлу. Потім можна передати дані до інтерактивних компонентів: - -```js -// Цей компонент запускається *лише* на сервері (або під час збирання). -async function Talks({ confId }) { - // 1. Ви на сервері, тож можете спілкуватися зі своїм шаром даних. Наявність API — необов'язкова. - const talks = await db.Talks.findAll({ confId }); - - // 2. Додавайте будь-яку кількість логіки рендерингу. Це не збільшить ваш бандл JavaScript. - const videos = talks.map(talk => talk.video); - - // 3. Передайте дані до компонентів, що запустяться в браузері. - return ; -} -``` - -App Router від Next.js також інтегрує [отримання даних із Suspense](/blog/2022/03/29/react-v18#suspense-in-data-frameworks). Це дає змогу задати стан завантаження (наприклад, каркасний елемент для заповнення (skeleton placeholder)) для різних частин інтерфейсу безпосередньо в дереві React: - -```js -}> - - -``` - -Серверні компоненти та Suspense — це радше функції React, аніж Next.js. Проте їхнє залучення на рівні фреймворку вимагає нетривіальних зусиль для реалізації. Наразі App Router Next.js — це найповніша імплементація. Команда React працює разом із розробниками бандлерів, щоб було легше реалізувати ці функції в наступному поколінні фреймворків. - - diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index ba900d404..b7ff0041b 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -25,17 +25,12 @@ "path": "/learn/installation", "routes": [ { -<<<<<<< HEAD - "title": "Початок нового React-проєкту", - "path": "/learn/start-a-new-react-project" -======= "title": "Creating a React App", "path": "/learn/creating-a-react-app" }, { "title": "Building a React Framework", "path": "/learn/building-a-react-framework" ->>>>>>> 49284218b1f5c94f930f8a9b305040dbe7d3dd48 }, { "title": "Інтеграція React у наявний проєкт", From 585bf87578bb8ff9107610c2c137139149b98f89 Mon Sep 17 00:00:00 2001 From: alinkedd Date: Tue, 18 Feb 2025 00:45:31 +0100 Subject: [PATCH 018/139] Add translations to Installation page --- src/content/learn/installation.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 30690ef92..3a76ae758 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -32,25 +32,25 @@ export default function App() { Щоб спробувати React локально на вашому комп'ютері, [завантажте цю HTML-сторінку.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Відкрийте її у редакторі та браузері! -## Початок React-проєкту {/*creating-a-react-app*/} +## Створення React-застосунку {/*creating-a-react-app*/} -Якщо ви хочете створити застосунок за допомогою React, [почніть React-проєкт](/learn/creating-a-react-app), використовуючи один із рекомендованих фреймворків. +Якщо ви хочете почати проєкт за допомогою React, [створіть React-застосунок](/learn/creating-a-react-app), використовуючи один із рекомендованих фреймворків. -## Build a React Framework {/*build-a-react-framework*/} +## Побудова React-фреймворку {/*build-a-react-framework*/} -If a framework is not a good fit for your project, or you prefer to start by building your own framework, you can [build your own React framework](/learn/building-a-react-framework). +Якщо фреймворк не годиться для вашого проєкту або ви бажаєте почати із самостійного створення його структури, [побудуйте власний React-фреймворк](/learn/building-a-react-framework). ## Інтегрувати React у наявний проєкт {/*add-react-to-an-existing-project*/} Якщо ви хочете використати React у власному застосунку або вебсайті, [інтегруйте React у наявний проєкт.](/learn/add-react-to-an-existing-project) -## Deprecated Options {/*deprecated-options*/} +## Застарілі варіанти {/*deprecated-options*/} ### Create React App (Deprecated) {/*create-react-app-deprecated*/} -Create React App is a deprecated tool, previously recommended for creating new React apps. If you want to start a new React app, you can [create a React app](/learn/creating-a-react-app) using a recommended framework. +Create React App — це застарілий інструмент, який раніше рекомендувався для створення нових React-застосунків. Якщо ви хочете почати новий проєкт за допомогою React, ви можете [створити React-застосунок](/learn/creating-a-react-app), використовуючи один із рекомендованих фреймворків. -For more information, see [Sunsetting Create React App](/blog/2025/02/14/sunsetting-create-react-app). +Дізнайтеся більше у статті ["Sunsetting Create React App"](/blog/2025/02/14/sunsetting-create-react-app). ## Подальші кроки {/*next-steps*/} From b5dd220e098c987b8c6fdc1952d3893acca749c3 Mon Sep 17 00:00:00 2001 From: alinkedd Date: Tue, 18 Feb 2025 00:46:18 +0100 Subject: [PATCH 019/139] Fix page name --- TRANSLATION.md | 2 +- src/content/learn/react-developer-tools.md | 12 ++++++------ src/sidebarLearn.json | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 31731ee2e..7a6d935d2 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -125,7 +125,7 @@ | development | розробка | | development mode | режим розробки | | developer tools | інструменти розробника | -| React developer tools | інструменти React розробника | +| React developer tools | інструменти розробника React | | DOM container | DOM-контейнер | | effect | ефект | | encapsulation | інкапсуляція | diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md index 76b8bbc5f..719521fb1 100644 --- a/src/content/learn/react-developer-tools.md +++ b/src/content/learn/react-developer-tools.md @@ -1,22 +1,22 @@ --- -title: Інструменти React розробника +title: Інструменти розробника React --- -Використовуйте інструменти React розробника (_React Developer Tools_) для інспектування React [компонентів](/learn/your-first-component), редагування їх [пропсів](/learn/passing-props-to-a-component) і [стану](/learn/state-a-components-memory), а також для виявлення проблем з продуктивністю. +Використовуйте інструменти розробника React (_React Developer Tools_) для інспектування React [компонентів](/learn/your-first-component), редагування їх [пропсів](/learn/passing-props-to-a-component) і [стану](/learn/state-a-components-memory), а також для виявлення проблем з продуктивністю. -* Як встановити інструменти React розробника +* Як встановити інструменти розробника React ## Розширення браузера {/*browser-extension*/} -Найпростіший спосіб налагодження вебсайтів, створених за допомогою React — встановити розширення браузера "Інструменти React розробника" (_React Developer Tools_). Воно доступне для декількох популярних браузерів: +Найпростіший спосіб налагодження вебсайтів, створених за допомогою React — встановити розширення браузера "Інструменти розробника React" (_React Developer Tools_). Воно доступне для декількох популярних браузерів: * [Встановити для **Chrome**](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=uk) * [Встановити для **Firefox**](https://addons.mozilla.org/uk/firefox/addon/react-devtools/) @@ -24,7 +24,7 @@ title: Інструменти React розробника Тепер, якщо ви відвідаєте вебсайт, **який створений за допомогою React**, ви побачите вкладки _Components_ і _Profiler_. -![Розширення 'Інструменти React розробника'](/images/docs/react-devtools-extension.png) +![Розширення 'Інструменти розробника React'](/images/docs/react-devtools-extension.png) ### Safari та інші браузери {/*safari-and-other-browsers*/} Для інших браузерів (наприклад, Safari) встановіть npm-пакет [`react-devtools`](https://www.npmjs.com/package/react-devtools): @@ -50,7 +50,7 @@ react-devtools Перезавантажте вебсайт у браузері, щоб переглянути його в інструментах розробника. -![Автономні 'Інструменти React розробника'](/images/docs/react-devtools-standalone.png) +![Автономні 'Інструменти розробника React'](/images/docs/react-devtools-standalone.png) ## Мобільний застосунок (React Native) {/*mobile-react-native*/} diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index b7ff0041b..5f87bd4ac 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -51,7 +51,7 @@ "path": "/learn/typescript" }, { - "title": "Інструменти React розробника", + "title": "Інструменти розробника React", "path": "/learn/react-developer-tools" }, { From 34e13df28171d9072383d12a4d89734bf24e203a Mon Sep 17 00:00:00 2001 From: Jason Qiu Date: Tue, 18 Feb 2025 08:39:15 +0800 Subject: [PATCH 020/139] Fix setup page (#7607) * Remove starting react project from setup page * Fix typo --- src/content/learn/setup.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/content/learn/setup.md b/src/content/learn/setup.md index 84608b427..2c46ee148 100644 --- a/src/content/learn/setup.md +++ b/src/content/learn/setup.md @@ -3,7 +3,7 @@ title: Setup --- -React integrates with tools like editors, TypeScript, browser extensions, and compliers. This section will help you get your environment set up. +React integrates with tools like editors, TypeScript, browser extensions, and compilers. This section will help you get your environment set up. @@ -23,10 +23,6 @@ React Developer Tools is a browser extension that can inspect React components, React Compiler is a tool that automatically optimizes your React app. [Learn more](/learn/react-compiler). -## Start a React Project from scratch {/*start-a-react-project-from-scratch*/} - -If you want to build your own framework, you can [start a React project from scratch](/learn/start-a-react-project-from-scratch). - ## Next steps {/*next-steps*/} Head to the [Quick Start](/learn) guide for a tour of the most important React concepts you will encounter every day. From 1a4183a6be2b4900c555743b058c0785ac8b7a56 Mon Sep 17 00:00:00 2001 From: Pranav Pise <160746099+TheCaptain1810@users.noreply.github.com> Date: Tue, 18 Feb 2025 06:10:03 +0530 Subject: [PATCH 021/139] fix: typo for issue #7491 (#7493) --- src/content/learn/tutorial-tic-tac-toe.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/learn/tutorial-tic-tac-toe.md b/src/content/learn/tutorial-tic-tac-toe.md index 6487e8007..1c61d180a 100644 --- a/src/content/learn/tutorial-tic-tac-toe.md +++ b/src/content/learn/tutorial-tic-tac-toe.md @@ -295,7 +295,7 @@ export default function Square() { } ``` -The _browser_ section should be displaying a square with a X in it like this: +The _browser_ section should be displaying a square with an X in it like this: ![x-filled square](../images/tutorial/x-filled-square.png) @@ -1325,7 +1325,7 @@ Let's recap what happens when a user clicks the top left square on your board to 1. `handleClick` uses the argument (`0`) to update the first element of the `squares` array from `null` to `X`. 1. The `squares` state of the `Board` component was updated, so the `Board` and all of its children re-render. This causes the `value` prop of the `Square` component with index `0` to change from `null` to `X`. -In the end the user sees that the upper left square has changed from empty to having a `X` after clicking it. +In the end the user sees that the upper left square has changed from empty to having an `X` after clicking it. @@ -1406,7 +1406,7 @@ But wait, there's a problem. Try clicking on the same square multiple times: The `X` is overwritten by an `O`! While this would add a very interesting twist to the game, we're going to stick to the original rules for now. -When you mark a square with a `X` or an `O` you aren't first checking to see if the square already has a `X` or `O` value. You can fix this by *returning early*. You'll check to see if the square already has a `X` or an `O`. If the square is already filled, you will `return` in the `handleClick` function early--before it tries to update the board state. +When you mark a square with an `X` or an `O` you aren't first checking to see if the square already has an `X` or `O` value. You can fix this by *returning early*. You'll check to see if the square already has an `X` or an `O`. If the square is already filled, you will `return` in the `handleClick` function early--before it tries to update the board state. ```js {2,3,4} function handleClick(i) { @@ -1556,7 +1556,7 @@ It does not matter whether you define `calculateWinner` before or after the `Boa -You will call `calculateWinner(squares)` in the `Board` component's `handleClick` function to check if a player has won. You can perform this check at the same time you check if a user has clicked a square that already has a `X` or and `O`. We'd like to return early in both cases: +You will call `calculateWinner(squares)` in the `Board` component's `handleClick` function to check if a player has won. You can perform this check at the same time you check if a user has clicked a square that already has an `X` or an `O`. We'd like to return early in both cases: ```js {2} function handleClick(i) { From c7099e36b0d8eb90d83908b5ba7b88261324f3ba Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 17 Feb 2025 20:02:08 -0500 Subject: [PATCH 022/139] Fix headings and add link (#7626) --- src/content/learn/build-a-react-app-from-scratch.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/learn/build-a-react-app-from-scratch.md b/src/content/learn/build-a-react-app-from-scratch.md index 50908d411..e5b396c7e 100644 --- a/src/content/learn/build-a-react-app-from-scratch.md +++ b/src/content/learn/build-a-react-app-from-scratch.md @@ -69,13 +69,13 @@ If you'd you're starting from scratch with React Native you'll need to use [Metr
-### Step 2: Build Common Application Patterns {/*step-2-build-common-application-patterns*/} +## Step 2: Build Common Application Patterns {/*step-2-build-common-application-patterns*/} The build tools listed above start off with a client-only, single-page app (SPA), but don't include any further solutions for common functionality like routing, data fetching, or styling. The React ecosystem includes many tools for these problems. We've listed a few that are widely used as a starting point, but feel free to choose other tools if those work better for you. -#### Routing {/*routing*/} +### Routing {/*routing*/} Routing determines what content or pages to display when a user visits a particular URL. You need to set up a router to map URLs to different parts of your app. You'll also need to handle nested routes, route parameters, and query parameters. Routers can be configured within your code, or defined based on your component folder and file structures. @@ -87,7 +87,7 @@ We suggest using: - [Tanstack Router](https://tanstack.com/router/latest) -#### Data Fetching {/*data-fetching*/} +### Data Fetching {/*data-fetching*/} Fetching data from a server or other data source is a key part of most applications. Doing this properly requires handling loading states, error states, and caching the fetched data, which can be complex. @@ -128,7 +128,7 @@ Since the build tool you select only support single page apps (SPAs) you'll need * **Streaming Server-side rendering (SSR)** renders a page on the server and sends the fully rendered page to the client. SSR can improve performance, but it can be more complex to set up and maintain than a single-page app. With the addition of streaming, SSR can be very complex to set up and maintain. See [Vite's SSR guide]( https://vite.dev/guide/ssr). -* **Static site generation (SSG)** generates static HTML files for your app at build time. SSG can improve performance, but it can be more complex to set up and maintain than server-side rendering. +* **Static site generation (SSG)** generates static HTML files for your app at build time. SSG can improve performance, but it can be more complex to set up and maintain than server-side rendering. See [Vite's SSG guide](https://vite.dev/guide/ssr.html#pre-rendering-ssg). * **React Server Components (RSC)** lets you mix build-time, server-only, and interactive components in a single React tree. RSC can improve performance, but it currently requires deep expertise to set up and maintain. See [Parcel's RSC examples](https://github.com/parcel-bundler/rsc-examples). From c726e7d1e4f717b72038c8a99510682813d395a9 Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 17 Feb 2025 20:16:14 -0500 Subject: [PATCH 023/139] Fix broken heading link (#7627) --- src/content/blog/2025/02/14/sunsetting-create-react-app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/blog/2025/02/14/sunsetting-create-react-app.md b/src/content/blog/2025/02/14/sunsetting-create-react-app.md index 03d09c111..c3ea22b91 100644 --- a/src/content/blog/2025/02/14/sunsetting-create-react-app.md +++ b/src/content/blog/2025/02/14/sunsetting-create-react-app.md @@ -11,7 +11,7 @@ February 14, 2025 by [Matt Carroll](https://twitter.com/mattcarrollcode) and [Ri -Today, we’re deprecating [Create React App](https://create-react-app.dev/) for new apps, and encouraging existing apps to migrate to a [framework](#how-to-migrate-to-a-framework), or to [migrate to a build tool](how-to-migrate-to-a-build-tool) like Vite, Parcel, or RSBuild. +Today, we’re deprecating [Create React App](https://create-react-app.dev/) for new apps, and encouraging existing apps to migrate to a [framework](#how-to-migrate-to-a-framework), or to [migrate to a build tool](#how-to-migrate-to-a-build-tool) like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by [building a React app from scratch](/learn/build-a-react-app-from-scratch). From aaf392ae24487016fc9e2378f667815ab12242c0 Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 17 Feb 2025 23:39:05 -0500 Subject: [PATCH 024/139] Fix more broken links (#7628) --- src/content/blog/2024/04/25/react-19-upgrade-guide.md | 2 +- src/content/reference/react-dom/static/prerender.md | 6 +++--- .../reference/react-dom/static/prerenderToNodeStream.md | 6 +++--- src/content/reference/rsc/server-components.md | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/content/blog/2024/04/25/react-19-upgrade-guide.md b/src/content/blog/2024/04/25/react-19-upgrade-guide.md index fbc4e378c..2f9802003 100644 --- a/src/content/blog/2024/04/25/react-19-upgrade-guide.md +++ b/src/content/blog/2024/04/25/react-19-upgrade-guide.md @@ -113,7 +113,7 @@ This will run the following codemods from `react-codemod`: - [`replace-string-ref`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-string-ref) - [`replace-act-import`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-act-import) - [`replace-use-form-state`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-use-form-state) -- [`prop-types-typescript`](https://codemod.com/registry/react-prop-types-typescript) +- [`prop-types-typescript`](https://github.com/reactjs/react-codemod#react-proptypes-to-prop-types) This does not include the TypeScript changes. See [TypeScript changes](#typescript-changes) below. diff --git a/src/content/reference/react-dom/static/prerender.md b/src/content/reference/react-dom/static/prerender.md index 6450e4a34..f1ef38b44 100644 --- a/src/content/reference/react-dom/static/prerender.md +++ b/src/content/reference/react-dom/static/prerender.md @@ -55,16 +55,16 @@ On the client, call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to * **optional** `bootstrapModules`: Like `bootstrapScripts`, but emits [`