`.
- Biasanya, Anda akan menggunakan *ref* untuk tindakan non-destruktif seperti fokus, *scrolling*, atau mengukur elemen-elemen DOM.
- Komponen tidak secara *default* mengekspos simpul DOM-nya. Anda dapat memilih untuk mengekspos simpul DOM dengan menggunakan `forwardRef` dan mengoper argumen `ref` kedua ke simpul yang spesifik.
- Hindari mengubah simpul DOM yang dikelola oleh React.
- Jika Anda mengubah simpul DOM yang dikelola oleh React, ubah bagian yang tidak perlu diperbarui oleh React.
+=======
+- Refs are a generic concept, but most often you'll use them to hold DOM elements.
+- You instruct React to put a DOM node into `myRef.current` by passing `
`.
+- Usually, you will use refs for non-destructive actions like focusing, scrolling, or measuring DOM elements.
+- A component doesn't expose its DOM nodes by default. You can opt into exposing a DOM node by using the `ref` prop.
+- Avoid changing DOM nodes managed by React.
+- If you do modify DOM nodes managed by React, modify parts that React has no reason to update.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
@@ -948,7 +988,7 @@ const catList = [];
for (let i = 0; i < 10; i++) {
catList.push({
id: i,
- imageUrl: 'https://placekitten.com/250/200?image=' + i
+ imageUrl: 'https://loremflickr.com/250/200/cat?lock=' + i
});
}
@@ -1065,7 +1105,7 @@ const catList = [];
for (let i = 0; i < 10; i++) {
catList.push({
id: i,
- imageUrl: 'https://placekitten.com/250/200?image=' + i
+ imageUrl: 'https://loremflickr.com/250/200/cat?lock=' + i
});
}
@@ -1117,7 +1157,11 @@ Buat agar saat tombol "Search" diklik, fokus masuk ke dalam input. Perhatikan ba
+<<<<<<< HEAD
Anda akan memerlukan `forwardRef` untuk memungkinkan eksposisi sebuah simpul DOM dari komponen Anda sendiri seperti `SearchInput`.
+=======
+You'll need to pass `ref` as a prop to opt into exposing a DOM node from your own component like `SearchInput`.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
@@ -1202,18 +1246,14 @@ export default function SearchButton({ onClick }) {
```
```js src/SearchInput.js
-import { forwardRef } from 'react';
-
-export default forwardRef(
- function SearchInput(props, ref) {
- return (
-
- );
- }
-);
+export default function SearchInput({ ref }) {
+ return (
+
+ );
+}
```
```css
diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md
index f34c382ed..7c46673e7 100644
--- a/src/content/learn/react-compiler.md
+++ b/src/content/learn/react-compiler.md
@@ -3,7 +3,7 @@ title: React Compiler
---
-This page will give you an introduction to the new experimental React Compiler and how to try it out successfully.
+This page will give you an introduction to React Compiler and how to try it out successfully.
@@ -13,20 +13,34 @@ These docs are still a work in progress. More documentation is available in the
* Getting started with the compiler
-* Installing the compiler and eslint plugin
+* Installing the compiler and ESLint plugin
* Troubleshooting
-React Compiler is a new experimental compiler that we've open sourced to get early feedback from the community. It still has rough edges and is not yet fully ready for production.
+React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules).
-React Compiler requires React 19 RC. If you are unable to upgrade to React 19, you may try a userspace implementation of the cache function as described in the [Working Group](https://github.com/reactwg/react-compiler/discussions/6). However, please note that this is not recommended and you should upgrade to React 19 when possible.
+The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`.
-React Compiler is a new experimental compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it.
+React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it.
-The compiler also includes an [eslint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. The plugin runs independently of the compiler and can be used even if you aren't using the compiler in your app. We recommend all React developers to use this eslint plugin to help improve the quality of your codebase.
+The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler.
+
+The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta:
+
+
+npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta
+
+
+Or, if you're using Yarn:
+
+
+yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta
+
+
+If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions.
### What does the compiler do? {/*what-does-the-compiler-do*/}
@@ -34,6 +48,10 @@ In order to optimize applications, React Compiler automatically memoizes your co
The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code.
+
+React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase.
+
+
If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand.
@@ -96,19 +114,9 @@ However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive
So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated.
-### What does the compiler assume? {/*what-does-the-compiler-assume*/}
-
-React Compiler assumes that your code:
-
-1. Is valid, semantic JavaScript
-2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`
-3. Follows the [Rules of React](https://react.dev/reference/rules)
-
-React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler).
-
### Should I try out the compiler? {/*should-i-try-out-the-compiler*/}
-Please note that the compiler is still experimental and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules).
+Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules).
**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better.
@@ -116,37 +124,32 @@ Please note that the compiler is still experimental and has many rough edges. Wh
In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler.
-### Checking compatibility {/*checking-compatibility*/}
-
-Prior to installing the compiler, you can first check to see if your codebase is compatible:
-
-
-npx react-compiler-healthcheck@latest
-
-
-This script will:
-
-- Check how many components can be successfully optimized: higher is better
-- Check for `` usage: having this enabled and followed means a higher chance that the [Rules of React](/reference/rules) are followed
-- Check for incompatible library usage: known libraries that are incompatible with the compiler
+### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/}
-As an example:
+React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler.
-Successfully compiled 8 out of 9 components.
-StrictMode usage not found.
-Found no usage of incompatible libraries.
+npm install -D eslint-plugin-react-compiler@beta
-### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/}
-
-React Compiler also powers an eslint plugin. The eslint plugin can be used **independently** of the compiler, meaning you can use the eslint plugin even if you don't use the compiler.
+Then, add it to your ESLint config:
-
-npm install eslint-plugin-react-compiler
-
+```js
+import reactCompiler from 'eslint-plugin-react-compiler'
+
+export default [
+ {
+ plugins: {
+ 'react-compiler': reactCompiler,
+ },
+ rules: {
+ 'react-compiler/react-compiler': 'error',
+ },
+ },
+]
+```
-Then, add it to your eslint config:
+Or, in the deprecated eslintrc config format:
```js
module.exports = {
@@ -154,14 +157,16 @@ module.exports = {
'eslint-plugin-react-compiler',
],
rules: {
- 'react-compiler/react-compiler': "error",
+ 'react-compiler/react-compiler': 'error',
},
}
```
-The eslint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase.
+The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase.
-**You don't have to fix all eslint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler.
+
+**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler.
+
### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/}
@@ -178,32 +183,53 @@ const ReactCompilerConfig = {
};
```
-In rare cases, you can also configure the compiler to run in "opt-in" mode using the `compilationMode: "annotation"` option. This makes it so the compiler will only compile components and hooks annotated with a `"use memo"` directive. Please note that the `annotation` mode is a temporary one to aid early adopters, and that we don't intend for the `"use memo"` directive to be used for the long term.
+When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app.
-```js {2,7}
+#### New projects {/*new-projects*/}
+
+If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior.
+
+### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/}
+
+React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17.
+
+
+npm install react-compiler-runtime@beta
+
+
+You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting:
+
+```js {3}
+// babel.config.js
const ReactCompilerConfig = {
- compilationMode: "annotation",
+ target: '18' // '17' | '18' | '19'
};
-// src/app.jsx
-export default function App() {
- "use memo";
- // ...
-}
+module.exports = function () {
+ return {
+ plugins: [
+ ['babel-plugin-react-compiler', ReactCompilerConfig],
+ ],
+ };
+};
```
-When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app.
+### Using the compiler on libraries {/*using-the-compiler-on-libraries*/}
-#### New projects {/*new-projects*/}
+React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm.
-If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior.
+Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary.
+
+Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation).
+
+Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify.
## Usage {/*installation*/}
### Babel {/*usage-with-babel*/}
-npm install babel-plugin-react-compiler
+npm install babel-plugin-react-compiler@beta
The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler.
@@ -252,36 +278,7 @@ export default defineConfig(() => {
### Next.js {/*usage-with-nextjs*/}
-Next.js has an experimental configuration to enable the React Compiler. It automatically ensures Babel is set up with `babel-plugin-react-compiler`.
-
-- Install Next.js canary, which uses React 19 Release Candidate
-- Install `babel-plugin-react-compiler`
-
-
-npm install next@canary babel-plugin-react-compiler
-
-
-Then configure the experimental option in `next.config.js`:
-
-```js {4,5,6}
-// next.config.js
-/** @type {import('next').NextConfig} */
-const nextConfig = {
- experimental: {
- reactCompiler: true,
- },
-};
-
-module.exports = nextConfig;
-```
-
-Using the experimental option ensures support for the React Compiler in:
-
-- App Router
-- Pages Router
-- Webpack (default)
-- Turbopack (opt-in through `--turbo`)
-
+Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information.
### Remix {/*usage-with-remix*/}
Install `vite-plugin-babel`, and add the compiler's Babel plugin to it:
@@ -314,44 +311,11 @@ export default defineConfig({
### Webpack {/*usage-with-webpack*/}
-You can create your own loader for React Compiler, like so:
-
-```js
-const ReactCompilerConfig = { /* ... */ };
-const BabelPluginReactCompiler = require('babel-plugin-react-compiler');
-
-function reactCompilerLoader(sourceCode, sourceMap) {
- // ...
- const result = transformSync(sourceCode, {
- // ...
- plugins: [
- [BabelPluginReactCompiler, ReactCompilerConfig],
- ],
- // ...
- });
-
- if (result === null) {
- this.callback(
- Error(
- `Failed to transform "${options.filename}"`
- )
- );
- return;
- }
-
- this.callback(
- null,
- result.code,
- result.map === null ? undefined : result.map
- );
-}
-
-module.exports = reactCompilerLoader;
-```
+A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack).
### Expo {/*usage-with-expo*/}
-Please refer to [Expo's docs](https://docs.expo.dev/preview/react-compiler/) to enable and use the React Compiler in Expo apps.
+Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps.
### Metro (React Native) {/*usage-with-react-native-metro*/}
@@ -371,22 +335,26 @@ To report issues, please first create a minimal repro on the [React Compiler Pla
You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler).
-### `(0 , _c) is not a function` error {/*0--_c-is-not-a-function-error*/}
+### What does the compiler assume? {/*what-does-the-compiler-assume*/}
-This occurs if you are not using React 19 RC and up. To fix this, [upgrade your app to React 19 RC](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) first.
+React Compiler assumes that your code:
-If you are unable to upgrade to React 19, you may try a userspace implementation of the cache function as described in the [Working Group](https://github.com/reactwg/react-compiler/discussions/6). However, please note that this is not recommended and you should upgrade to React 19 when possible.
+1. Is valid, semantic JavaScript.
+2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`.
+3. Follows the [Rules of React](https://react.dev/reference/rules).
+
+React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler).
### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/}
-[React Devtools](/learn/react-developer-tools) (v5.0+) has built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler.
+[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler.
### Something is not working after compilation {/*something-is-not-working-after-compilation*/}
-If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all eslint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized.
+If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized.
Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases.
-If your app doesn't work properly after compilation and you aren't seeing any eslint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component).
+If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component).
```js {2}
function SuspiciousComponent() {
diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md
index f37009eeb..27d28679c 100644
--- a/src/content/learn/react-developer-tools.md
+++ b/src/content/learn/react-developer-tools.md
@@ -56,17 +56,21 @@ Reload website Anda sekarang untuk melihatnya di React Developer Tools.

## Mobile (React Native) {/*mobile-react-native*/}
+<<<<<<< HEAD
React Developer Tools dapat digunakan untuk memeriksa aplikasi yang dibangun dengan [React Native](https://reactnative.dev/) juga.
Cara termudah untuk menggunakan React Developer Tools adalah dengan menginstalnya secara global:
```bash
# Yarn
yarn global add react-devtools
+=======
-# Npm
-npm install -g react-devtools
-```
+To inspect apps built with [React Native](https://reactnative.dev/), you can use [React Native DevTools](https://reactnative.dev/docs/react-native-devtools), the built-in debugger that deeply integrates React Developer Tools. All features work identically to the browser extension, including native element highlighting and selection.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
+
+[Learn more about debugging in React Native.](https://reactnative.dev/docs/debugging)
+<<<<<<< HEAD
Selanjutnya buka React Developer Tools dari terminal:
```bash
react-devtools
@@ -78,3 +82,6 @@ React Developer Tools akan terhubung ke aplikasi React Native lokal yang sedang
[Pelajari lebih lanjut tentang debugging React Native.](https://reactnative.dev/docs/debugging)
+=======
+> For versions of React Native earlier than 0.76, please use the standalone build of React DevTools by following the [Safari and other browsers](#safari-and-other-browsers) guide above.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md
index a66b666e5..2628cda30 100644
--- a/src/content/learn/render-and-commit.md
+++ b/src/content/learn/render-and-commit.md
@@ -70,9 +70,15 @@ Cobalah memberi komentar di luar dari `root.render()` dan lihat komponen tersebu
Setelah komponen telah pertama kali di*render*, Anda dapat memicu *render* kembali dengan memperbarui *state* menggunakan [fungsi `set`.](/reference/react/useState#setstate) Mengubah *state* komponen Anda otomatis akan membuat antrian proses *render*. (Anda dapat membayangkan ada sebuah restoran dimana pengunjung memesan teh, hidangan penutup, dan semua hal tersebut dipesan setelah melakukan pesanan pertama, tergantung pada keadaan haus atau lapar dari pengunjung)
+<<<<<<< HEAD
+=======
+
+
+
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
## Langkah 2: React me-render komponen Anda {/*step-2-react-renders-your-components*/}
@@ -84,7 +90,11 @@ Setelah Anda memicu sebuah *render*, React memanggil komponen Anda untuk menemuk
Proses ini bersifat rekursif: jika komponen yang diperbarui mengembalikan beberapa komponen lain, React akan me-*render* komponen _itu_ berikutnya, dan jika komponen itu juga mengembalikan sesuatum React akan me-*render* komponen _itu_ berikutnya, dan seterusnya. Proses tersebut akan berlanjut sampai tidak terdapat komponen bersarang dan React mengetahui persis apa yang harus ditampilkan pada layar.
+<<<<<<< HEAD
Dalam contoh berikut, React akan memanggil `Gallery()` dan `Image()` beberapa kali:
+=======
+In the following example, React will call `Gallery()` and `Image()` several times:
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
@@ -148,10 +158,17 @@ Perilaku bawaan dari proses *render* semua komponen bersarang di dalam komponen
## Langkah 3: React mengirimkan perubahan kepada DOM {/*step-3-react-commits-changes-to-the-dom*/}
+<<<<<<< HEAD
Setelah proses _render_ (memanggil) komponen Anda, React akan memodifikasi DOM.
* **Untuk _render_ awal,** React akan menggunakan [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) DOM API untuk meletakkan semua simpul DOM yang telah dibuat ke dalam layar.
* **Untuk _render_ ulang,** React akan menerapkan operasi minimal yang diperlukan (dihitung saat proses *render*!) untuk membuat DOM sama dengan keluaran *render* terakhir.
+=======
+After rendering (calling) your components, React will modify the DOM.
+
+* **For the initial render,** React will use the [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) DOM API to put all the DOM nodes it has created on screen.
+* **For re-renders,** React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
**React hanya mengubah simpul DOM jika ada perbedaan diantara proses _render_.** Sebagai contoh, berikut terdapat komponen yang me-*render* ulang dengan properti berbeda yang dikirimkan setiap detik. Perhatikan bagaimana Anda dapat menambahkan beberapa teks ke dalam ``, memperbarui nilai ``, tetapi teks tersebut tidak menghilang saat komponen me-*render* ulang:
diff --git a/src/content/learn/setup.md b/src/content/learn/setup.md
new file mode 100644
index 000000000..2c46ee148
--- /dev/null
+++ b/src/content/learn/setup.md
@@ -0,0 +1,28 @@
+---
+title: Setup
+---
+
+
+React integrates with tools like editors, TypeScript, browser extensions, and compilers. 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).
+
+## 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/state-a-components-memory.md b/src/content/learn/state-a-components-memory.md
index bd9331cc2..80f31db43 100644
--- a/src/content/learn/state-a-components-memory.md
+++ b/src/content/learn/state-a-components-memory.md
@@ -1455,7 +1455,11 @@ Jika *linter* Anda [disetel untuk React](/learn/editor-setup#linting), Anda seha
#### Menghapus state yang tidak perlu {/*remove-unnecessary-state*/}
+<<<<<<< HEAD
Saat tombol ditekan, pada contoh di bawah, sebuah kotak dialog akan muncul untuk diisi pengguna dan akan menambilkan pesan untuk menyapa mereka. Anda sudah coba menggunakan *state* untuk namanya, namun karena suatu hal dia tetap menampilkan "Halo, !"
+=======
+When the button is clicked, this example should ask for the user's name and then display an alert greeting them. You tried to use state to keep the name, but for some reason the first time it shows "Hello, !", and then "Hello, [name]!" with the previous input every time after.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
Untuk memperbaiki kode di bawah, hilangkan variabel *state* yang tidak perlu. (Kita akan bahas [mengapa hal tersebut tidak bekerja](/learn/state-as-a-snapshot) nanti.)
diff --git a/src/content/learn/synchronizing-with-effects.md b/src/content/learn/synchronizing-with-effects.md
index 7e0e6ebc4..77542d933 100644
--- a/src/content/learn/synchronizing-with-effects.md
+++ b/src/content/learn/synchronizing-with-effects.md
@@ -629,7 +629,11 @@ Lihat contoh di bawah ini untuk cara menangani pola umum.
### Mengontrol *widget* di luar React {/*controlling-non-react-widgets*/}
+<<<<<<< HEAD
Terkadang Anda perlu menambahkan *widget* UI yang tidak ditulis untuk React. Sebagai contoh, katakanlah Anda menambahkan komponen peta ke halaman Anda. Komponen ini memiliki metode `setZoomLevel()`, dan Anda ingin menjaga tingkat *zoom* tetap sinkron dengan variabel *state* `zoomLevel` dalam kode React Anda. *Effect* Anda akan terlihat seperti ini:
+=======
+Sometimes you need to add UI widgets that aren't written in React. For example, let's say you're adding a map component to your page. It has a `setZoomLevel()` method, and you'd like to keep the zoom level in sync with a `zoomLevel` state variable in your React code. Your Effect would look similar to this:
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
```js
useEffect(() => {
diff --git a/src/content/learn/thinking-in-react.md b/src/content/learn/thinking-in-react.md
index caa3d1915..cb79fcee8 100644
--- a/src/content/learn/thinking-in-react.md
+++ b/src/content/learn/thinking-in-react.md
@@ -265,11 +265,19 @@ Pada langkah sebelumnya, Anda menemukan dua bagian status dalam aplikasi ini: te
Sekarang mari kita bahas strateginya:
+<<<<<<< HEAD
1. **Identifikasi komponen yang menggunakan state:**
* `ProductTable` perlu memfilter daftar produk berdasarkan status tersebut (teks pencarian dan nilai kotak centang).
* `SearchBar` perlu menampilkan status tersebut (teks pencarian dan nilai kotak centang).
1. **Temukan induk yang sama:** Komponen induk pertama yang dimiliki oleh kedua komponen tersebut adalah `FilterableProductTable`.
2. **Tentukan di mana state berada**: Kita akan menyimpan teks filter dan nilai state kotak centang di `FilterableProductTable`.
+=======
+1. **Identify components that use state:**
+ * `ProductTable` needs to filter the product list based on that state (search text and checkbox value).
+ * `SearchBar` needs to display that state (search text and checkbox value).
+2. **Find their common parent:** The first parent component both components share is `FilterableProductTable`.
+3. **Decide where the state lives**: We'll keep the filter text and checked state values in `FilterableProductTable`.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
Jadi nilai state akan berada di dalam `FilterableProductTable`.
diff --git a/src/content/learn/tutorial-tic-tac-toe.md b/src/content/learn/tutorial-tic-tac-toe.md
index 5496ee37c..f61468821 100644
--- a/src/content/learn/tutorial-tic-tac-toe.md
+++ b/src/content/learn/tutorial-tic-tac-toe.md
@@ -295,7 +295,11 @@ export default function Square() {
}
```
+<<<<<<< HEAD
Bagian _browser_ seharusnya menampilkan sebuah kotak dengan tanda X di dalamnya seperti ini:
+=======
+The _browser_ section should be displaying a square with an X in it like this:
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7

@@ -1133,7 +1137,11 @@ Memanggil fungsi `setSquares` akan membuat React mengetahui bahwa state dari kom
+<<<<<<< HEAD
JavaScript mendukung [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) yang berarti fungsi dalam (misalnya `handleClick`) memiliki akses ke variabel dan fungsi yang didefinisikan di fungsi luar (misalnya `Board`). Fungsi `handleClick` dapat membaca state `squares` dan memanggil metode `setSquares` karena keduanya didefinisikan di dalam fungsi `Board`.
+=======
+JavaScript supports [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) which means an inner function (e.g. `handleClick`) has access to variables and functions defined in an outer function (e.g. `Board`). The `handleClick` function can read the `squares` state and call the `setSquares` method because they are both defined inside of the `Board` function.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
@@ -1325,7 +1333,11 @@ Mari kita rekap apa yang terjadi ketika pengguna mengeklik kotak kiri atas pada
1. `handleClick` menggunakan argumen (`0`) untuk meng-update elemen pertama dari array `squares` dari `null` menjadi `X`.
1. State `squares` dari komponen `Board` telah diperbarui, sehingga `Board` dan semua anak komponennya di-render ulang. Hal ini menyebabkan prop `value` dari komponen `Square` dengan indeks `0` berubah dari `null` menjadi `X`.
+<<<<<<< HEAD
Pada akhirnya pengguna akan melihat bahwa kotak kiri atas telah berubah dari kosong menjadi bertanda `X` setelah mengekliknya.
+=======
+In the end the user sees that the upper left square has changed from empty to having an `X` after clicking it.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
@@ -1406,7 +1418,11 @@ Tapi tunggu, ada masalah. Coba klik kotak yang sama beberapa kali:
Tanda `X` ditimpa oleh tanda `O`! Meskipun hal ini akan menambah sentuhan yang sangat menarik pada gim ini, kami akan tetap berpegang pada aturan asli untuk saat ini.
+<<<<<<< HEAD
Ketika Anda menandai kotak dengan `X` atau `O`, Anda tidak memeriksa terlebih dahulu apakah kotak tersebut telah memiliki nilai `X` atau `O`. Anda dapat memperbaikinya dengan *return lebih awal*. Anda akan memeriksa apakah kotak tersebut sudah memiliki nilai `X` atau `O`. Jika kotak sudah terisi, Anda akan `return` dalam fungsi `handleClick` lebih awal--sebelum fungsi ini mencoba untuk meng-update state papan.
+=======
+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.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
```js {2,3,4}
function handleClick(i) {
@@ -1556,7 +1572,11 @@ Tidak masalah apakah Anda mendefinisikan `calculateWinner` sebelum atau sesudah
+<<<<<<< HEAD
Anda akan memanggil `calculateWinner(squares)` dalam fungsi `handleClick` komponen `Board` untuk memeriksa apakah pemain telah menang. Anda dapat melakukan pengecekan ini bersamaan dengan pengecekan apakah pengguna telah mengklik kotak yang telah memiliki tanda `X` atau `O`. Kita ingin kembali lebih awal dalam kedua kasus tersebut:
+=======
+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:
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
```js {2}
function handleClick(i) {
diff --git a/src/content/learn/updating-objects-in-state.md b/src/content/learn/updating-objects-in-state.md
index ead94cc14..09de34a35 100644
--- a/src/content/learn/updating-objects-in-state.md
+++ b/src/content/learn/updating-objects-in-state.md
@@ -58,6 +58,7 @@ Berikut adalah contoh kode yang menampung objek di dalam *state* untuk mereprese
```js
import { useState } from 'react';
+
export default function MovingDot() {
const [position, setPosition] = useState({
x: 0,
@@ -127,6 +128,7 @@ Perhatikan bahwa sekarang titik merah sudah mengikuti kursor Anda ketika Anda me
```js
import { useState } from 'react';
+
export default function MovingDot() {
const [position, setPosition] = useState({
x: 0,
@@ -377,7 +379,11 @@ Perhatikan bahwa `...` sintaksis *spread* sebenarnya adalah "dangkal"--benda-ben
#### Menggunakan satu event handler untuk beberapa bidang {/*using-a-single-event-handler-for-multiple-fields*/}
+<<<<<<< HEAD
Anda juga bisa menggunakan tanda `[` dan `]` di dalam definisi objek untuk menentukan sebuah properti dengan nama yang dinamis. Berikut adalah contoh yang sama, tetapi dengan satu *event handler* daripada tiga yang berbeda:
+=======
+You can also use the `[` and `]` braces inside your object definition to specify a property with a dynamic name. Here is the same example, but with a single event handler instead of three different ones:
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md
index 5342a27ed..23578f955 100644
--- a/src/content/learn/you-might-not-need-an-effect.md
+++ b/src/content/learn/you-might-not-need-an-effect.md
@@ -408,9 +408,15 @@ function Game() {
Ada dua masalah dengan kode ini.
+<<<<<<< HEAD
Salah satu masalahnya adalah hal ini sangat tidak efisien: komponen (dan turunannya) harus di-*render* ulang di antara setiap panggilan `set` dalam rantai. Dalam contoh di atas, dalam kasus terburuk (`setCard` → *render* → `setGoldCardCount` → *render* → `setRound` → *render* → `setIsGameOver` → *render*) ada tiga *rendering* ulang yang tidak diperlukan pada pohon di bawah ini.
Meskipun tidak lambat, seiring berkembangnya kode Anda, Anda akan menghadapi kasus di mana "rantai" yang Anda tulis tidak sesuai dengan persyaratan baru. Bayangkan Anda menambahkan cara untuk menelusuri sejarah gerakan permainan. Anda akan melakukannya dengan memperbarui setiap variabel *state* ke nilai dari masa lalu. Namun, menyetel *state* `card` ke nilai dari masa lalu akan memicu rantai *Effect* lagi dan mengubah data yang Anda tampilkan. Kode seperti ini seringkali kaku dan rapuh.
+=======
+The first problem is that it is very inefficient: the component (and its children) have to re-render between each `set` call in the chain. In the example above, in the worst case (`setCard` → render → `setGoldCardCount` → render → `setRound` → render → `setIsGameOver` → render) there are three unnecessary re-renders of the tree below.
+
+The second problem is that even if it weren't slow, as your code evolves, you will run into cases where the "chain" you wrote doesn't fit the new requirements. Imagine you are adding a way to step through the history of the game moves. You'd do it by updating each state variable to a value from the past. However, setting the `card` state to a value from the past would trigger the Effect chain again and change the data you're showing. Such code is often rigid and fragile.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
Dalam hal ini, lebih baik menghitung apa yang Anda bisa selama *rendering*, dan sesuaikan *state* di *event handler*:
diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md
index 5c50be07e..f4a041532 100644
--- a/src/content/reference/react-dom/client/createRoot.md
+++ b/src/content/reference/react-dom/client/createRoot.md
@@ -49,7 +49,14 @@ Aplikasi yang sepenuhnya dibuat dengan React biasanya cukup memanggil `createRoo
* **opsional** `onRecoverableError`: *Callback* yang dipanggil saat React berhasil pulih secara otomatis dari kesalahan. Dipanggil dengan `error` yang dikembalikan React, dan obyek `errorInfo` berisi `componentStack`. Beberapa kesalahan yang dapat dipulihkan mungkin akan berisi kesalahan aslinya sebagai `error.cause`.
* **opsional** `identifierPrefix`: Awalan string yang digunakan React untuk ID yang dihasilkan oleh [`useId`.](/reference/react/useId) Berguna untuk mencegah konflik saat menggunakan banyak akar pada halaman yang sama.
+<<<<<<< HEAD
#### Kembalian {/*returns*/}
+=======
+ * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`.
+ * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown, and an `errorInfo` object containing the `componentStack`.
+ * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with an `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`.
+ * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
`createRoot` mengembalikan sebuah objek dengan dua *method*: [`render`](#root-render) dan [`unmount`.](#root-unmount)
@@ -142,7 +149,7 @@ Biasanya, Anda cukup menjalankan kode ini sekali saja pada *startup*. Kode ini a
-```html index.html
+```html public/index.html
My app
@@ -342,10 +349,15 @@ export default function App({counter}) {
Pemanggilan `render` berulang kali biasanya tidak wajar. Pada umumnya komponen Anda akan [memperbarui *state*](/reference/react/useState).
+<<<<<<< HEAD
### Menampilkan dialog untuk *error* yang tidak ditangkap {/*show-a-dialog-for-uncaught-errors*/}
+=======
+### Error logging in production {/*error-logging-in-production*/}
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
-
+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`:
+<<<<<<< HEAD
`onCaughtError` hanya tersedia di rilis Canary React terbaru.
@@ -788,92 +800,28 @@ import { createRoot } from "react-dom/client";
import App from "./App.js";
import {reportCaughtError} from "./reportError";
import "./styles.css";
+=======
+```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]]
+import { createRoot } from "react-dom/client";
+import { reportCaughtError } from "./reportError";
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
const container = document.getElementById("root");
const root = createRoot(container, {
onCaughtError: (error, errorInfo) => {
- if (error.message !== 'Known error') {
+ if (error.message !== "Known error") {
reportCaughtError({
- error,
+ error,
componentStack: errorInfo.componentStack,
});
}
- }
-});
-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");
- }
-
- 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 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": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0",
- "react-error-boundary": "4.0.3"
},
- "main": "/index.js"
-}
+});
```
-
+The onCaughtError option is a function called with two arguments:
+<<<<<<< HEAD
### Menampilkan dialog untuk *error* yang dapat dipulihkan {/*displaying-a-dialog-for-recoverable-errors*/}
React dapat secara otomatis me-*render* komponen untuk kedua kalinya guna mencoba memulihkan dari *error* yang terjadi saat me-*render*. Jika berhasil, React akan me-log *error* yang dapat dipulihkan ke konsol untuk memberi tahu pengembang aplikasi. Untuk mengatasi perilaku ini, Anda dapat memberikan opsi *root* `onRecoverableError` opsional:
@@ -903,238 +851,113 @@ Pengaturan onRecoverableError adalah fungsi yang d
2. Obyek errorInfo yang mengandung componentStack dari *error* tersebut.
Anda dapat menggunakan opsi *root* `onRecoverableError` untuk menampilkan dialog *error*:
+=======
+1. The error that was thrown.
+2. An errorInfo object that contains the componentStack of the error.
-
-
-```html index.html hidden
-
-
-
- My app
-
-
-
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-
-
-
-```
-
-```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;
-}
+Together with `onUncaughtError` and `onRecoverableError`, you can can implement your own error reporting system:
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
-pre.nowrap {
- text-wrap: nowrap;
-}
+
-.hidden {
- display: none;
+```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);
}
-```
-
-```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 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 { createRoot } from "react-dom/client";
import App from "./App.js";
-import {reportRecoverableError} from "./reportError";
-import "./styles.css";
+import {
+ onCaughtErrorProd,
+ onRecoverableErrorProd,
+ onUncaughtErrorProd,
+} from "./reportError";
const container = document.getElementById("root");
const root = createRoot(container, {
- onRecoverableError: (error, errorInfo) => {
- reportRecoverableError({
- error,
- cause: error.cause,
- 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";
+import { Component, useState } from "react";
-// 🚩 Bug: Never do this. This will force an error.
-let errorThrown = false;
-export default function App() {
- 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.
-
-
- >
- );
+function Boom() {
+ foo.bar = "baz";
}
-function fallbackRender() {
- return (
-
-
Error Boundary
-
Something went wrong.
-
- );
-}
+class ErrorBoundary extends Component {
+ state = { hasError: false };
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true };
+ }
-function Throw({error}) {
- // Simulate an external value changing during concurrent render.
- errorThrown = true;
- foo.bar = 'baz';
+ render() {
+ if (this.state.hasError) {
+ return Something went wrong.
;
+ }
+ return this.props.children;
+ }
}
-```
-```json package.json hidden
-{
- "dependencies": {
- "react": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0",
- "react-error-boundary": "4.0.3"
- },
- "main": "/index.js"
+export default function App() {
+ const [triggerUncaughtError, settriggerUncaughtError] = useState(false);
+ const [triggerCaughtError, setTriggerCaughtError] = useState(false);
+
+ return (
+ <>
+
+ {triggerUncaughtError && }
+
+ {triggerCaughtError && (
+
+
+
+ )}
+ >
+ );
}
```
+<<<<<<< HEAD
---
## Pemecahan masalah {/*troubleshooting*/}
+=======
+## Troubleshooting {/*troubleshooting*/}
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
### Saya telah membuat sebuah akar, namun tidak ada yang tampil {/*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 d406304dc..1da9967f8 100644
--- a/src/content/reference/react-dom/client/hydrateRoot.md
+++ b/src/content/reference/react-dom/client/hydrateRoot.md
@@ -39,11 +39,18 @@ React akan ditambahkan ke dalam HTML yang ada di dalam `domNode`, dan mengambil
* `reactNode`: "React node" yang digunakan untuk me-render HTML yang ada. Biasanya berupa bagian dari JSX seperti `` yang dengan *method* `ReactDOM Server` seperti `renderToPipeableStream()`.
+<<<<<<< HEAD
* **opsional** `options`: Objek dengan opsi untuk akar React.
* **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`.
* **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown and an `errorInfo` object containing the `componentStack`.
* **opsional** `onRecoverableError`: *Callback* yang dipanggil saat React berhasil pulih secara otomatis dari kesalahan. Dipanggil dengan `error` yang dikembalikan React, dan obyek `errorInfo` berisi `componentStack`. Beberapa kesalahan yang dapat dipulihkan mungkin akan berisi kesalahan aslinya sebagai `error.cause`.
* **opsional** `identifierPrefix`: Awalan string yang digunakan React untuk ID yang dihasilkan oleh [`useId`.](/reference/react/useId) Berguna untuk menghindari konflik ketika menggunakan beberapa akar pada halaman yang sama. Harus awalan yang sama dengan yang digunakan pada *server*.
+=======
+ * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`.
+ * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown and an `errorInfo` object containing the `componentStack`.
+ * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with the `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`.
+ * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix as used on the server.
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
#### Kembalian {/*returns*/}
@@ -373,10 +380,15 @@ export default function App({counter}) {
Tidak lazim untuk memanggil [`root.render`](#root-render) pada *hydrated root*. Biasanya, Anda akan [memperbarui *state*](/reference/react/useState) di dalam salah satu komponen sebagai gantinya.
+<<<<<<< HEAD
### Menunjukkan dialog untuk *error* yang tidak ditangkap {/*show-a-dialog-for-uncaught-errors*/}
+=======
+### Error logging in production {/*error-logging-in-production*/}
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
-
+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`:
+<<<<<<< HEAD
`onUncaughtError` hanya tersedia di rilis Canary React terbaru.
@@ -571,53 +583,23 @@ export function reportRecoverableError({error, cause, componentStack}) {
```
```js src/index.js active
+=======
+```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]]
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
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 { reportCaughtError } from "./reportError";
const container = document.getElementById("root");
-const root = hydrateRoot(container, , {
- onUncaughtError: (error, errorInfo) => {
- if (error.message !== 'Known error') {
- reportUncaughtError({
+const root = hydrateRoot(container, {
+ onCaughtError: (error, errorInfo) => {
+ if (error.message !== "Known error") {
+ reportCaughtError({
error,
- componentStack: errorInfo.componentStack
+ componentStack: errorInfo.componentStack,
});
}
- }
-});
-```
-
-```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:
-
-
- );
-}
-```
-
-```json package.json hidden
-{
- "dependencies": {
- "react": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0"
},
+<<<<<<< HEAD
"main": "/index.js"
}
```
@@ -652,252 +634,116 @@ const root = hydrateRoot(
}
);
root.render();
+=======
+});
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
```
Pengaturan onUncaughtError adalah fungsi yang dipanggil dengan dua argumen:
+<<<<<<< HEAD
1. error yang ditangkap oleh *boundary*.
2. Obyek errorInfo yang berisi componentStack dari *error* tersebut.
Anda dapat menggunakan opsi *root* `onUncaughtError` untuk menunjukkan dialog *error* atau memfilter *error* yang diketahui dari *logging*:
+=======
+1. The error that was thrown.
+2. An errorInfo object that contains the componentStack of the error.
-
+Together with `onUncaughtError` and `onRecoverableError`, you can implement your own error reporting system:
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
-```html index.html hidden
-
-
-
- My app
-
-
-
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-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
+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);
}
-```
-```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');
+export function onCaughtErrorProd(error, errorInfo) {
+ if (error.message !== "Known error") {
+ reportError({ type: "Caught", error, errorInfo });
}
- // 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 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 { hydrateRoot } 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 = hydrateRoot(container, , {
- onCaughtError: (error, errorInfo) => {
- if (error.message !== 'Known error') {
- reportCaughtError({
- 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 { ErrorBoundary } from "react-error-boundary";
+import { Component, useState } from "react";
-export default function App() {
- const [error, setError] = useState(null);
-
- function handleUnknown() {
- setError("unknown");
+function Boom() {
+ foo.bar = "baz";
+}
+
+class ErrorBoundary extends Component {
+ state = { hasError: false };
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true };
}
- function handleKnown() {
- setError("known");
+ render() {
+ if (this.state.hasError) {
+ return Something went wrong.
;
+ }
+ return this.props.children;
}
-
- return (
- <>
- {
- setError(null);
- }}
- >
- {error != null && }
- This error will not show the error dialog:
-
- This error will show the error dialog:
-
-
-
- >
- );
}
-function fallbackRender({ resetErrorBoundary }) {
+export default function App() {
+ const [triggerUncaughtError, settriggerUncaughtError] = useState(false);
+ const [triggerCaughtError, setTriggerCaughtError] = useState(false);
+
return (
-
-
Error Boundary
-
Something went wrong.
-
-
+ <>
+
+ {triggerUncaughtError && }
+
+ {triggerCaughtError && (
+
+
+
+ )}
+ >
);
}
-
-function Throw({error}) {
- if (error === "known") {
- throw new Error('Known error')
- } else {
- foo.bar = 'baz';
- }
-}
```
+<<<<<<< HEAD
```json package.json hidden
{
"dependencies": {
@@ -945,6 +791,9 @@ Anda dapat menggunakan opsi *root* `onUncaughtError` untuk menunjukkan dialog *e
```html index.html hidden
+=======
+```html public/index.html hidden
+>>>>>>> fc29603434ec04621139738f4740caed89d659a7
@@ -952,226 +801,12 @@ Anda dapat menggunakan opsi *root* `onUncaughtError` untuk menunjukkan dialog *e
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-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": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0",
- "react-error-boundary": "4.0.3"
- },
- "main": "/index.js"
-}
-```
-
## Troubleshooting {/*troubleshooting*/}
diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md
index 47e499aca..383e45a38 100644
--- a/src/content/reference/react-dom/components/common.md
+++ b/src/content/reference/react-dom/components/common.md
@@ -247,6 +247,7 @@ Berikut *events* yang aktif pada beberapa sumber daya seperti [`