);
}
diff --git a/src/components/MDX/Link.tsx b/src/components/MDX/Link.tsx
index 8986d07a5..7bf041e56 100644
--- a/src/components/MDX/Link.tsx
+++ b/src/components/MDX/Link.tsx
@@ -13,7 +13,7 @@ function Link({
className,
children,
...props
-}: JSX.IntrinsicElements['a']) {
+}: React.AnchorHTMLAttributes) {
const classes =
'inline text-link dark:text-link-dark border-b border-link border-opacity-0 hover:border-opacity-100 duration-100 ease-in transition leading-normal';
const modifiedChildren = Children.toArray(children).map((child: any) => {
@@ -41,11 +41,8 @@ function Link({
{modifiedChildren}
) : (
-
- {/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
-
- {modifiedChildren}
-
+
+ {modifiedChildren}
)}
>
diff --git a/src/components/MDX/Sandpack/DownloadButton.tsx b/src/components/MDX/Sandpack/DownloadButton.tsx
index 4181dbe95..4d206fff8 100644
--- a/src/components/MDX/Sandpack/DownloadButton.tsx
+++ b/src/components/MDX/Sandpack/DownloadButton.tsx
@@ -7,19 +7,22 @@ import {useSandpack} from '@codesandbox/sandpack-react';
import {IconDownload} from '../../Icon/IconDownload';
export interface DownloadButtonProps {}
-let supportsImportMap: boolean | void;
+let supportsImportMap = false;
+
+function subscribe(cb: () => void) {
+ // This shouldn't actually need to update, but this works around
+ // https://github.com/facebook/react/issues/26095
+ let timeout = setTimeout(() => {
+ supportsImportMap =
+ (HTMLScriptElement as any).supports &&
+ (HTMLScriptElement as any).supports('importmap');
+ cb();
+ }, 0);
+ return () => clearTimeout(timeout);
+}
function useSupportsImportMap() {
- function subscribe() {
- // It never updates.
- return () => {};
- }
function getCurrentValue() {
- if (supportsImportMap === undefined) {
- supportsImportMap =
- (HTMLScriptElement as any).supports &&
- (HTMLScriptElement as any).supports('importmap');
- }
return supportsImportMap;
}
function getServerSnapshot() {
diff --git a/src/components/Search.tsx b/src/components/Search.tsx
index 0e8f84f0d..2a9743ec3 100644
--- a/src/components/Search.tsx
+++ b/src/components/Search.tsx
@@ -22,11 +22,7 @@ export interface SearchProps {
}
function Hit({hit, children}: any) {
- return (
-
- {children}
-
- );
+ return {children};
}
// Copy-pasted from @docsearch/react to avoid importing the whole bundle.
diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md
new file mode 100644
index 000000000..81da3fd00
--- /dev/null
+++ b/src/content/blog/2023/05/03/react-canaries.md
@@ -0,0 +1,94 @@
+---
+title: "React Canaries: Enabling Incremental Feature Rollout Outside Meta"
+---
+
+May 3, 2023 by [Dan Abramov](https://twitter.com/dan_abramov), [Sophie Alpert](https://twitter.com/sophiebits), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Andrew Clark](https://twitter.com/acdlite)
+
+---
+
+
+
+We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final, before they're released in a stable version--similar to how Meta has long used bleeding-edge versions of React internally. We are introducing a new officially supported [Canary release channel](/community/versioning-policy#canary-channel). It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule.
+
+
+
+---
+
+## tl;dr {/*tldr*/}
+
+* We're introducing an officially supported [Canary release channel](/community/versioning-policy#canary-channel) for React. Since it's officially supported, if any regressions land, we'll treat them with a similar urgency to bugs in stable releases.
+* Canaries let you start using individual new React features before they land in the semver-stable releases.
+* Unlike the [Experimental](/community/versioning-policy#experimental-channel) channel, React Canaries only include features that we reasonably believe to be ready for adoption. We encourage frameworks to consider bundling pinned Canary React releases.
+* We will announce breaking changes and new features on our blog as they land in Canary releases.
+* **As always, React continues to follow semver for every Stable release.**
+
+## How React features are usually developed {/*how-react-features-are-usually-developed*/}
+
+Typically, every React feature has gone through the same stages:
+
+1. We develop an initial version and prefix it with `experimental_` or `unstable_`. The feature is only available in the `experimental` release channel. At this point, the feature is expected to change significantly.
+2. We find a team at Meta willing to help us test this feature and provide feedback on it. This leads to a round of changes. As the feature becomes more stable, we work with more teams at Meta to try it out.
+3. Eventually, we feel confident in the design. We remove the prefix from the API name, and make the feature available on the `main` branch by default, which most Meta products use. At this point, any team at Meta can use this feature.
+4. As we build confidence in the direction, we also post an RFC for the new feature. At this point we know the design works for a broad set of cases, but we might make some last minute adjustments.
+5. When we are close to cutting an open source release, we write documentation for the feature and finally release the feature in a stable React release.
+
+This playbook works well for most features we've released so far. However, there can be a significant gap between when the feature is generally ready to use (step 3) and when it is released in open source (step 5).
+
+**We'd like to offer the React community an option to follow the same approach as Meta, and adopt individual new features earlier (as they become available) without having to wait for the next release cycle of React.**
+
+As always, all React features will eventually make it into a Stable release.
+
+## Can we just do more minor releases? {/*can-we-just-do-more-minor-releases*/}
+
+Generally, we *do* use minor releases for introducing new features.
+
+However, this isn't always possible. Sometimes, new features are interconnected with *other* new features which have not yet been fully completed and that we're still actively iterating on. We can't release them separately because their implementations are related. We can't version them separately because they affect the same packages (for example, `react` and `react-dom`). And we need to keep the ability to iterate on the pieces that aren't ready without a flurry of major version releases, which semver would require us to do.
+
+At Meta, we've solved this problem by building React from the `main` branch, and manually updating it to a specific pinned commit every week. This is also the approach that React Native releases have been following for the last several years. Every *stable* release of React Native is pinned to a specific commit from the `main` branch of the React repository. This lets React Native include important bugfixes and incrementally adopt new React features at the framework level without getting coupled to the global React release schedule.
+
+We would like to make this workflow available to other frameworks and curated setups. For example, it lets a framework *on top of* React include a React-related breaking change *before* this breaking change gets included into a stable React release. This is particularly useful because some breaking changes only affect framework integrations. This lets a framework release such a change in its own minor version without breaking semver.
+
+Rolling releases with the Canaries channel will allow us to have a tighter feedback loop and ensure that new features get comprehensive testing in the community. This workflow is closer to how TC39, the JavaScript standards committee, [handles changes in numbered stages](https://tc39.es/process-document/). New React features may be available in frameworks built on React before they are in a React stable release, just as new JavaScript features ship in browsers before they are officially ratified as part of the specification.
+
+## Why not use experimental releases instead? {/*why-not-use-experimental-releases-instead*/}
+
+Although you *can* technically use [Experimental releases](/community/versioning-policy#canary-channel), we recommend against using them in production because experimental APIs can undergo significant breaking changes on their way to stabilization (or can even be removed entirely). While Canaries can also contain mistakes (as with any release), going forward we plan to announce any significant breaking changes in Canaries on our blog. Canaries are the closest to the code Meta runs internally, so you can generally expect them to be relatively stable. However, you *do* need to keep the version pinned and manually scan the GitHub commit log when updating between the pinned commits.
+
+**We expect that most people using React outside a curated setup (like a framework) will want to continue using the Stable releases.** However, if you're building a framework, you might want to consider bundling a Canary version of React pinned to a particular commit, and update it at your own pace. The benefit of that is that it lets you ship individual completed React features and bugfixes earlier for your users and at your own release schedule, similar to how React Native has been doing it for the last few years. The downside is that you would take on additional responsibility to review which React commits are being pulled in and communicate to your users which React changes are included with your releases.
+
+If you're a framework author and want to try this approach, please get in touch with us.
+
+## Announcing breaking changes and new features early {/*announcing-breaking-changes-and-new-features-early*/}
+
+Canary releases represent our best guess of what will go into the next stable React release at any given time.
+
+Traditionally, we've only announced breaking changes at the *end* of the release cycle (when doing a major release). Now that Canary releases are an officially supported way to consume React, we plan to shift towards announcing breaking changes and significant new features *as they land* in Canaries. For example, if we merge a breaking change that will go out in a Canary, we will write a post about it on the React blog, including codemods and migration instructions if necessary. Then, if you're a framework author cutting a major release that updates the pinned React canary to include that change, you can link to our blog post from your release notes. Finally, when a stable major version of React is ready, we will link to those already published blog posts, which we hope will help our team make progress faster.
+
+We plan to document APIs as they land in Canaries--even if these APIs are not yet available outside of them. APIs that are only available in Canaries will be marked with a special note on the corresponding pages. This will include APIs like [`use`](https://github.com/reactjs/rfcs/pull/229), and some others (like `cache` and `createServerContext`) which we'll send RFCs for.
+
+## Canaries must be pinned {/*canaries-must-be-pinned*/}
+
+If you decide to adopt the Canary workflow for your app or framework, make sure you always pin the *exact* version of the Canary you're using. Since Canaries are pre-releases, they may still include breaking changes.
+
+## Example: React Server Components {/*example-react-server-components*/}
+
+As we [announced in March](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components), the React Server Components conventions have been finalized, and we do not expect significant breaking changes related to their user-facing API contract. However, we can't release support for React Server Components in a stable version of React yet because we are still working on several intertwined framework-only features (such as [asset loading](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#asset-loading)) and expect more breaking changes there.
+
+This means that React Server Components are ready to be adopted by frameworks. However, until the next major React release, the only way for a framework to adopt them is to ship a pinned Canary version of React. (To avoid bundling two copies of React, frameworks that wish to do this would need to enforce resolution of `react` and `react-dom` to the pinned Canary they ship with their framework, and explain that to their users. As an example, this is what Next.js App Router does.)
+
+## Testing libraries against both Stable and Canary versions {/*testing-libraries-against-both-stable-and-canary-versions*/}
+
+We do not expect library authors to test every single Canary release since it would be prohibitively difficult. However, just as when we [originally introduced the different React pre-release channels three years ago](https://legacy.reactjs.org/blog/2019/10/22/react-release-channels.html), we encourage libraries to run tests against *both* the latest Stable and latest Canary versions. If you see a change in behavior that wasn't announced, please file a bug in the React repository so that we can help diagnose it. We expect that as this practice becomes widely adopted, it will reduce the amount of effort necessary to upgrade libraries to new major versions of React, since accidental regressions would be found as they land.
+
+
+
+Strictly speaking, Canary is not a *new* release channel--it used to be called Next. However, we've decided to rename it to avoid confusion with Next.js. We're announcing it as a *new* release channel to communicate the new expectations, such as Canaries being an officially supported way to use React.
+
+
+
+## Stable releases work like before {/*stable-releases-work-like-before*/}
+
+We are not introducing any changes to stable React releases.
+
+
+
diff --git a/src/content/blog/index.md b/src/content/blog/index.md
index 3459965f6..fc8a2969b 100644
--- a/src/content/blog/index.md
+++ b/src/content/blog/index.md
@@ -10,6 +10,11 @@ This blog is the official source for the updates from the React team. Anything i
+
+
+Traditionally, new React features used to only be available at Meta first, and land in the open source releases later. We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final--similar to how Meta uses React internally. We are introducing a new officially supported Canary release channel. It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule.
+
+
diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md
index b1860ac0d..06711db6d 100644
--- a/src/content/community/conferences.md
+++ b/src/content/community/conferences.md
@@ -10,36 +10,6 @@ Do you know of a local React.js conference? Add it here! (Please keep the list c
## Upcoming Conferences {/*upcoming-conferences*/}
-### Reactathon 2023 {/*reactathon-2023*/}
-May 2 - 3, 2023. San Francisco, CA, USA
-
-[Website](https://reactathon.com) - [Twitter](https://twitter.com/reactathon) - [YouTube](https://www.youtube.com/realworldreact)
-
-### RemixConf 2023 {/*remixconf-2023*/}
-May, 2023. Salt Lake City, UT
-
-[Website](https://remix.run/conf/2023) - [Twitter](https://twitter.com/remix_run)
-
-### App.js Conf 2023 {/*appjs-conf-2023*/}
-May 10 - 12, 2023. In-person in Kraków, Poland + remote
-
-[Website](https://appjs.co) - [Twitter](https://twitter.com/appjsconf)
-
-### Chain React 2023 {/*chain-react-2023*/}
-May 17 - 19, 2023. Portland, OR, USA
-
-[Website](https://chainreactconf.com/) - [Twitter](https://twitter.com/ChainReactConf) - [Facebook](https://www.facebook.com/ChainReactConf/) - [Youtube](https://www.youtube.com/channel/UCwpSzVt7QpLDbCnPXqR97-g/playlists)
-
-### Render(ATL) 2023 🍑 {/*renderatl-2023-*/}
-May 31 - June 2, 2023. Atlanta, GA, USA
-
-[Website](https://renderatl.com) - [Discord](https://www.renderatl.com/discord) - [Twitter](https://twitter.com/renderATL) - [Instagram](https://www.instagram.com/renderatl/) - [Facebook](https://www.facebook.com/renderatl/) - [LinkedIn](https://www.linkedin.com/company/renderatl) - [Podcast](https://www.renderatl.com/culture-and-code#/)
-
-### React Summit 2023 {/*react-summit-2023*/}
-June 2 & 6, 2023. In-person in Amsterdam, Netherlands + remote first interactivity (hybrid event)
-
-[Website](https://reactsummit.com) - [Twitter](https://twitter.com/reactsummit) - [Facebook](https://www.facebook.com/reactamsterdam) - [Videos](https://portal.gitnation.org/events/react-summit-2023)
-
### React Norway 2023 {/*react-norway-2023*/}
June 16th, 2023. Larvik, Norway
@@ -60,11 +30,6 @@ August 17 & 18, 2023. Salt Lake City, UT, USA
[Website](https://www.reactrally.com/) - [Twitter](https://twitter.com/ReactRally) - [Instagram](https://www.instagram.com/reactrally/)
-### React On The Beach 2023 {/*react-on-the-beach-2023*/}
-September 07, 2023. Amsterdam, Netherlands (In-person event)
-
-[Website](https://reactonthebeach.com/) - [Twitter](https://twitter.com/reactonthebeach)
-
### React India 2023 {/*react-india-2023*/}
Oct 5 - 7, 2023. In-person in Goa, India (hybrid event) + Oct 3 2023 - remote day
@@ -87,6 +52,36 @@ December 8 & 12, 2023. In-person in Berlin, Germany + remote first interactivity
## Past Conferences {/*past-conferences*/}
+### React Summit 2023 {/*react-summit-2023*/}
+June 2 & 6, 2023. In-person in Amsterdam, Netherlands + remote first interactivity (hybrid event)
+
+[Website](https://reactsummit.com) - [Twitter](https://twitter.com/reactsummit) - [Facebook](https://www.facebook.com/reactamsterdam) - [Videos](https://portal.gitnation.org/events/react-summit-2023)
+
+### Render(ATL) 2023 🍑 {/*renderatl-2023-*/}
+May 31 - June 2, 2023. Atlanta, GA, USA
+
+[Website](https://renderatl.com) - [Discord](https://www.renderatl.com/discord) - [Twitter](https://twitter.com/renderATL) - [Instagram](https://www.instagram.com/renderatl/) - [Facebook](https://www.facebook.com/renderatl/) - [LinkedIn](https://www.linkedin.com/company/renderatl) - [Podcast](https://www.renderatl.com/culture-and-code#/)
+
+### Chain React 2023 {/*chain-react-2023*/}
+May 17 - 19, 2023. Portland, OR, USA
+
+[Website](https://chainreactconf.com/) - [Twitter](https://twitter.com/ChainReactConf) - [Facebook](https://www.facebook.com/ChainReactConf/) - [Youtube](https://www.youtube.com/channel/UCwpSzVt7QpLDbCnPXqR97-g/playlists)
+
+### App.js Conf 2023 {/*appjs-conf-2023*/}
+May 10 - 12, 2023. In-person in Kraków, Poland + remote
+
+[Website](https://appjs.co) - [Twitter](https://twitter.com/appjsconf)
+
+### RemixConf 2023 {/*remixconf-2023*/}
+May, 2023. Salt Lake City, UT
+
+[Website](https://remix.run/conf/2023) - [Twitter](https://twitter.com/remix_run)
+
+### Reactathon 2023 {/*reactathon-2023*/}
+May 2 - 3, 2023. San Francisco, CA, USA
+
+[Website](https://reactathon.com) - [Twitter](https://twitter.com/reactathon) - [YouTube](https://www.youtube.com/realworldreact)
+
### React Miami 2023 {/*react-miami-2023*/}
April 20 - 21, 2023. Miami, FL, USA
diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md
index b6ffc96de..68d5b8eb1 100644
--- a/src/content/community/versioning-policy.md
+++ b/src/content/community/versioning-policy.md
@@ -79,13 +79,18 @@ This section will be most relevant to developers who work on frameworks, librari
Each of React's release channels is designed for a distinct use case:
-- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **Use this for all user-facing React applications.**
-- [**Next**](#next-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next minor semver release. Use this for integration testing between React and third party projects.
+- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **User-facing applications that consume React directly use this channel.**
+- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next semver release. **[Frameworks or other curated setups may choose to use this channel with a pinned version of React.](/blog/2023/05/03/react-canaries) You can also Canaries for integration testing between React and third party projects.**
- [**Experimental**](#experimental-channel) includes experimental APIs and features that aren't available in the stable releases. These also track the main branch, but with additional feature flags turned on. Use this to try out upcoming features before they are released.
-All releases are published to npm, but only Latest uses semantic versioning. Prereleases (those in the Next and Experimental channels) have versions generated from a hash of their contents and the commit date, e.g. `0.0.0-68053d940-20210623` for Next and `0.0.0-experimental-68053d940-20210623` for Experimental.
+All releases are published to npm, but only Latest uses semantic versioning. Prereleases (those in the Canary and Experimental channels) have versions generated from a hash of their contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503` for Canary and `0.0.0-experimental-388686f29-20230503` for Experimental.
-**The only officially supported release channel for user-facing applications is Latest**. Next and Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest.
+**Both Latest and Canary channels are officially supported for user-facing applications, but with different expectations**:
+
+* Latest releases follow the traditional semver model.
+* Canary releases [must be pinned](/blog/2023/05/03/react-canaries) and may include breaking changes. They exist for curated setups (like frameworks) that want to gradually release new React features and bugfixes on their own release schedule.
+
+The Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest.
By publishing prereleases to the same registry that we use for stable releases, we are able to take advantage of the many tools that support the npm workflow, like [unpkg](https://unpkg.com) and [CodeSandbox](https://codesandbox.io).
@@ -93,51 +98,51 @@ By publishing prereleases to the same registry that we use for stable releases,
Latest is the channel used for stable React releases. It corresponds to the `latest` tag on npm. It is the recommended channel for all React apps that are shipped to real users.
-**If you're not sure which channel you should use, it's Latest.** If you're a React developer, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases)
+**If you're not sure which channel you should use, it's Latest.** If you're using React directly, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases)
-### Next channel {/*next-channel*/}
+### Canary channel {/*canary-channel*/}
-The Next channel is a prerelease channel that tracks the main branch of the React repository. We use prereleases in the Next channel as release candidates for the Latest channel. You can think of Next as a superset of Latest that is updated more frequently.
+The Canary channel is a prerelease channel that tracks the main branch of the React repository. We use prereleases in the Canary channel as release candidates for the Latest channel. You can think of Canary as a superset of Latest that is updated more frequently.
-The degree of change between the most recent Next release and the most recent Latest release is approximately the same as you would find between two minor semver releases. However, **the Next channel does not conform to semantic versioning.** You should expect occasional breaking changes between successive releases in the Next channel.
+The degree of change between the most recent Canary release and the most recent Latest release is approximately the same as you would find between two minor semver releases. However, **the Canary channel does not conform to semantic versioning.** You should expect occasional breaking changes between successive releases in the Canary channel.
-**Do not use prereleases in user-facing applications.**
+**Do not use prereleases in user-facing applications directly unless you're following the [Canary workflow](/blog/2023/05/03/react-canaries).**
-Releases in Next are published with the `next` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `0.0.0-68053d940-20210623`.
+Releases in Canary are published with the `canary` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503`.
-#### Using the next channel for integration testing {/*using-the-next-channel-for-integration-testing*/}
+#### Using the canary channel for integration testing {/*using-the-canary-channel-for-integration-testing*/}
-The Next channel is designed to support integration testing between React and other projects.
+The Canary channel also supports integration testing between React and other projects.
All changes to React go through extensive internal testing before they are released to the public. However, there are a myriad of environments and configurations used throughout the React ecosystem, and it's not possible for us to test against every single one.
If you're the author of a third party React framework, library, developer tool, or similar infrastructure-type project, you can help us keep React stable for your users and the entire React community by periodically running your test suite against the most recent changes. If you're interested, follow these steps:
- Set up a cron job using your preferred continuous integration platform. Cron jobs are supported by both [CircleCI](https://circleci.com/docs/2.0/triggers/#scheduled-builds) and [Travis CI](https://docs.travis-ci.com/user/cron-jobs/).
-- In the cron job, update your React packages to the most recent React release in the Next channel, using `next` tag on npm. Using the npm cli:
+- In the cron job, update your React packages to the most recent React release in the Canary channel, using `canary` tag on npm. Using the npm cli:
```console
- npm update react@next react-dom@next
+ npm update react@canary react-dom@canary
```
Or yarn:
```console
- yarn upgrade react@next react-dom@next
+ yarn upgrade react@canary react-dom@canary
```
- Run your test suite against the updated packages.
- If everything passes, great! You can expect that your project will work with the next minor React release.
- If something breaks unexpectedly, please let us know by [filing an issue](https://github.com/facebook/react/issues).
-A project that uses this workflow is Next.js. (No pun intended! Seriously!) You can refer to their [CircleCI configuration](https://github.com/zeit/next.js/blob/c0a1c0f93966fe33edd93fb53e5fafb0dcd80a9e/.circleci/config.yml) as an example.
+A project that uses this workflow is Next.js. You can refer to their [CircleCI configuration](https://github.com/zeit/next.js/blob/c0a1c0f93966fe33edd93fb53e5fafb0dcd80a9e/.circleci/config.yml) as an example.
### Experimental channel {/*experimental-channel*/}
-Like Next, the Experimental channel is a prerelease channel that tracks the main branch of the React repository. Unlike Next, Experimental releases include additional features and APIs that are not ready for wider release.
+Like Canary, the Experimental channel is a prerelease channel that tracks the main branch of the React repository. Unlike Canary, Experimental releases include additional features and APIs that are not ready for wider release.
-Usually, an update to Next is accompanied by a corresponding update to Experimental. They are based on the same source revision, but are built using a different set of feature flags.
+Usually, an update to Canary is accompanied by a corresponding update to Experimental. They are based on the same source revision, but are built using a different set of feature flags.
-Experimental releases may be significantly different than releases to Next and Latest. **Do not use Experimental releases in user-facing applications.** You should expect frequent breaking changes between releases in the Experimental channel.
+Experimental releases may be significantly different than releases to Canary and Latest. **Do not use Experimental releases in user-facing applications.** You should expect frequent breaking changes between releases in the Experimental channel.
Releases in Experimental are published with the `experimental` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `0.0.0-experimental-68053d940-20210623`.
@@ -147,11 +152,11 @@ Experimental features are ones that are not ready to be released to the wider pu
For example, if the Experimental channel had existed when we announced Hooks, we would have released Hooks to the Experimental channel weeks before they were available in Latest.
-You may find it valuable to run integration tests against Experimental. This is up to you. However, be advised that Experimental is even less stable than Next. **We do not guarantee any stability between Experimental releases.**
+You may find it valuable to run integration tests against Experimental. This is up to you. However, be advised that Experimental is even less stable than Canary. **We do not guarantee any stability between Experimental releases.**
#### How can I learn more about experimental features? {/*how-can-i-learn-more-about-experimental-features*/}
-Experimental features may or may not be documented. Usually, experiments aren't documented until they are close to shipping in Next or Latest.
+Experimental features may or may not be documented. Usually, experiments aren't documented until they are close to shipping in Canary or Latest.
If a feature is not documented, they may be accompanied by an [RFC](https://github.com/reactjs/rfcs).
diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md
index cfd52320a..8a5368809 100644
--- a/src/content/learn/conditional-rendering.md
+++ b/src/content/learn/conditional-rendering.md
@@ -1,24 +1,24 @@
---
-title: Conditional Rendering
+title: Условный рендеринг
---
-Your components will often need to display different things depending on different conditions. In React, you can conditionally render JSX using JavaScript syntax like `if` statements, `&&`, and `? :` operators.
+Вашим компонентам нужно часто отображать различные вещи в зависимости от различных условий. В React вы можете рендерить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :`
-* How to return different JSX depending on a condition
-* How to conditionally include or exclude a piece of JSX
-* Common conditional syntax shortcuts you’ll encounter in React codebases
+- Как вернуть разный JSX, в зависимости от условия.
+- Как в зависимости от условий добавить или убрать часть JSX.
+- Часто встречающиеся сокращения синтаксиса условных выражений, с которыми вы столкнётесь в проектах на React.
-## Conditionally returning JSX {/*conditionally-returning-jsx*/}
+## Условный возврат JSX {/*conditionally-returning-jsx*/}
-Let’s say you have a `PackingList` component rendering several `Item`s, which can be marked as packed or not:
+Допустим, у вас есть компонент `PackingList`, который рендерит несколько компонентов `Item`, который могут быть отмечены как упакованные или нет:
@@ -26,23 +26,22 @@ Let’s say you have a `PackingList` component rendering several `Item`s, which
function Item({ name, isPacked }) {
return
@@ -51,10 +50,11 @@ export default function PackingList() {
```
+
-Notice that some of the `Item` components have their `isPacked` prop set to `true` instead of `false`. You want to add a checkmark (✔) to packed items if `isPacked={true}`.
+Обратите внимание, что у некоторых компонентов `Item` проп `isPacked` имеет значение `true`, вместо значения `false`. Если `isPacked={true}`, вы хотите добавить галочку(✔) к упакованным вещам.
-You can write this as an [`if`/`else` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) like so:
+Можно реализовать это с помощью [управляющей конструкции `if`/`else`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом:
```js
if (isPacked) {
@@ -63,7 +63,7 @@ if (isPacked) {
return
{name}
;
```
-If the `isPacked` prop is `true`, this code **returns a different JSX tree.** With this change, some of the items get a checkmark at the end:
+Если `isPacked` проп равен `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, некоторые вещи получат галочку в конце:
@@ -78,19 +78,19 @@ function Item({ name, isPacked }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -100,13 +100,13 @@ export default function PackingList() {
-Try editing what gets returned in either case, and see how the result changes!
+Попробуйте отредактировать то, что возвращается в обоих случаях, и посмотрите, как изменится результат!
-Notice how you're creating branching logic with JavaScript's `if` and `return` statements. In React, control flow (like conditions) is handled by JavaScript.
+Обратите внимание, как вы создаёте разветвлённую логику с помощью операторов JavaScript `if` и `return`. В React управление потоком выполнения (например, условия) обрабатывает JavaScript.
-### Conditionally returning nothing with `null` {/*conditionally-returning-nothing-with-null*/}
+### Условно возвращаем ничего, с помощью `null` {/*conditionally-returning-nothing-with-null*/}
-In some situations, you won't want to render anything at all. For example, say you don't want to show packed items at all. A component must return something. In this case, you can return `null`:
+В некоторых ситуациях вы вообще не захотите ничего рендерить. Например, вы не хотите показывать упакованные предметы. Компонент должен что-то возвращать. В этом случае вы можете вернуть `null`:
```js
if (isPacked) {
@@ -115,7 +115,7 @@ if (isPacked) {
return
{name}
;
```
-If `isPacked` is true, the component will return nothing, `null`. Otherwise, it will return JSX to render.
+Если `isPacked` равен true, то компонент не вернёт ничего, `null`. В противном случае, он вернёт JSX для рендеринга.
@@ -130,19 +130,19 @@ function Item({ name, isPacked }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -152,23 +152,23 @@ export default function PackingList() {
-In practice, returning `null` from a component isn't common because it might surprise a developer trying to render it. More often, you would conditionally include or exclude the component in the parent component's JSX. Here's how to do that!
+На практике возврат `null` из компонента не является обычным делом, поскольку это может удивить разработчика, пытающегося его рендерить. Чаще всего вы будете условно включать или исключать компонент в JSX родительского компонента. Вот как это сделать!
-## Conditionally including JSX {/*conditionally-including-jsx*/}
+## Условное включение JSX {/*conditionally-including-jsx*/}
-In the previous example, you controlled which (if any!) JSX tree would be returned by the component. You may already have noticed some duplication in the render output:
+В предыдущем примере вы контролировали, какое JSX дерево будет возвращено компонентом (если вообще будет!). Возможно, вы уже заметили некоторое дублирование в выводе рендера:
```js
{name} ✔
```
-is very similar to
+очень похоже на
```js
{name}
```
-Both of the conditional branches return `
...
`:
+Обе ветки условия возвращают `
...
`:
```js
if (isPacked) {
@@ -177,13 +177,13 @@ if (isPacked) {
return
{name}
;
```
-While this duplication isn't harmful, it could make your code harder to maintain. What if you want to change the `className`? You'd have to do it in two places in your code! In such a situation, you could conditionally include a little JSX to make your code more [DRY.](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
+Хоть и такое дублирование не вредно, но оно может усложнить поддержку вашего кода. Что если вы захотите изменить `className`? Вам придётся делать это в двух местах вашего кода! В такой ситуации вы можете условно включить небольшой JSX, чтобы сделать ваш код более [DRY.](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself).
-### Conditional (ternary) operator (`? :`) {/*conditional-ternary-operator--*/}
+### Условный (тернанрый) оператор (`? :`) {/*conditional-ternary-operator--*/}
-JavaScript has a compact syntax for writing a conditional expression -- the [conditional operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) or "ternary operator".
+В JavaScript есть компактный синтаксис для записи условного выражения — [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор".
-Instead of this:
+Вместо этого:
```js
if (isPacked) {
@@ -192,7 +192,7 @@ if (isPacked) {
return
{name}
;
```
-You can write this:
+Вы можете написать это:
```js
return (
@@ -202,17 +202,17 @@ return (
);
```
-You can read it as *"if `isPacked` is true, then (`?`) render `name + ' ✔'`, otherwise (`:`) render `name`"*.
+Вы можете читать это как *"если `isPacked` равно true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерим `name`"*.
-#### Are these two examples fully equivalent? {/*are-these-two-examples-fully-equivalent*/}
+#### Эти два примера полностью эквивалентны? {/*are-these-two-examples-fully-equivalent*/}
-If you're coming from an object-oriented programming background, you might assume that the two examples above are subtly different because one of them may create two different "instances" of `
`. But JSX elements aren't "instances" because they don't hold any internal state and aren't real DOM nodes. They're lightweight descriptions, like blueprints. So these two examples, in fact, *are* completely equivalent. [Preserving and Resetting State](/learn/preserving-and-resetting-state) goes into detail about how this works.
+Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера немного отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
`. Но JSX-элементы не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными DOM-узлами. Это лёгкие описания, как чертежи. На самом деле эти два примера *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает.
-Now let's say you want to wrap the completed item's text into another HTML tag, like `` to strike it out. You can add even more newlines and parentheses so that it's easier to nest more JSX in each of the cases:
+Теперь предположим, что вы хотите обернуть текст завершённого элемента в другой HTML-тег, например ``, чтобы вычеркнуть его. Вы можете добавить ещё больше переносов строк и круглых скобок, чтобы было проще вкладывать JSX в каждом из случаев:
@@ -234,19 +234,19 @@ function Item({ name, isPacked }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -256,11 +256,11 @@ export default function PackingList() {
-This style works well for simple conditions, but use it in moderation. If your components get messy with too much nested conditional markup, consider extracting child components to clean things up. In React, markup is a part of your code, so you can use tools like variables and functions to tidy up complex expressions.
+Этот стиль хорошо работает для простых условий, но используйте его в меру. Если ваши компоненты становятся запутанными из-за слишком большого количества вложенной условной разметки, подумайте об выделении дочерних компонентов, чтобы навести порядок. В React разметка является частью кода, поэтому вы можете использовать такие инструменты, как переменные и функции, чтобы привести в порядок сложные выражения.
-### Logical AND operator (`&&`) {/*logical-and-operator-*/}
+### Логический оператор И(`&&`) {/*logical-and-operator-*/}
-Another common shortcut you'll encounter is the [JavaScript logical AND (`&&`) operator.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#:~:text=The%20logical%20AND%20(%20%26%26%20)%20operator,it%20returns%20a%20Boolean%20value.) Inside React components, it often comes up when you want to render some JSX when the condition is true, **or render nothing otherwise.** With `&&`, you could conditionally render the checkmark only if `isPacked` is `true`:
+Еще одно часто встречающееся сокращение [JavaScript логический оператор И (`&&`).](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React-компонентов он часто используется, когда вам нужно отрендерить JSX, когда условие true, **или не рендерить ничего.** С помощью `&&` вы можете условно рендерить галочку, если `isPacked` равно `true`:
```js
return (
@@ -270,9 +270,9 @@ return (
);
```
-You can read this as *"if `isPacked`, then (`&&`) render the checkmark, otherwise, render nothing"*.
+Вы можете читать это как *"если `isPacked`, тогда (`&&`) рендерим галочку, в противном случае -- ничего не рендерим"*.
-Here it is in action:
+Вот это в действии:
@@ -288,19 +288,19 @@ function Item({ name, isPacked }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -310,38 +310,38 @@ export default function PackingList() {
-A [JavaScript && expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND) returns the value of its right side (in our case, the checkmark) if the left side (our condition) is `true`. But if the condition is `false`, the whole expression becomes `false`. React considers `false` as a "hole" in the JSX tree, just like `null` or `undefined`, and doesn't render anything in its place.
+[JavaScript выражение &&](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение правой части (в нашем случае это галочка), если левая часть (наше условие) является `true`. Но если наше условие — `false`, тогда всё выражение становится `false`. React рассматривает `false` как "пустое место" в дереве JSX, прямо как `null` или `undefined`, и ничего не рендерит на этом месте.
-**Don't put numbers on the left side of `&&`.**
+**Не ставь числа по левую сторону `&&`.**
-To test the condition, JavaScript converts the left side to a boolean automatically. However, if the left side is `0`, then the whole expression gets that value (`0`), and React will happily render `0` rather than nothing.
+Для проверки условия JavaScript автоматически преобразует левую часть в булевое значение. Однако, если левая часть равна `0`, то всё выражение получает это значение (`0`), и React будет с радостью рендерить `0` вместо ничего.
-For example, a common mistake is to write code like `messageCount &&
New messages
`. It's easy to assume that it renders nothing when `messageCount` is `0`, but it really renders the `0` itself!
+Например, распространённой ошибкой является написание кода вида `messageCount &&
Новые сообщения
`. Легко предположить, что ничего не отрендерено, когда `messageCount` равно `0`, но на самом деле будет рендериться `0`!
-To fix it, make the left side a boolean: `messageCount > 0 &&
New messages
`.
+Чтобы исправить это, сделайте левую часть булевым значением: `messageCount > 0 &&
Новые сообщения
`.
-### Conditionally assigning JSX to a variable {/*conditionally-assigning-jsx-to-a-variable*/}
+### Условное присвоение JSX к переменной {/*conditionally-assigning-jsx-to-a-variable*/}
-When the shortcuts get in the way of writing plain code, try using an `if` statement and a variable. You can reassign variables defined with [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), so start by providing the default content you want to display, the name:
+Когда сокращения мешают написанию понятного кода, то попробуйте использовать `if` оператор и переменную. Вы можете переназначать переменные, объявленные с помощью [`let`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let), поэтому начните с предоставления содержимого по умолчанию, которое вы хотите отобразить, например, name:
```js
let itemContent = name;
```
-Use an `if` statement to reassign a JSX expression to `itemContent` if `isPacked` is `true`:
+Используйте `if` оператор, чтобы переназначить JSX-выражение `itemContent`, если `isPacked` равно `true`:
```js
if (isPacked) {
- itemContent = name + " ✔";
+ itemContent = name + ' ✔';
}
```
-[Curly braces open the "window into JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Embed the variable with curly braces in the returned JSX tree, nesting the previously calculated expression inside of JSX:
+[Фигурные скобки открывают "окно в мир JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Вставьте переменную с помощью фигурных скобок в возвращаемое дерево JSX, вложив ранее вычисленное выражение внутрь JSX:
```js
@@ -349,7 +349,7 @@ if (isPacked) {
```
-This style is the most verbose, but it's also the most flexible. Here it is in action:
+Этот стиль самый многословный, но и самый гибкий. Вот он в действии:
@@ -357,7 +357,7 @@ This style is the most verbose, but it's also the most flexible. Here it is in a
function Item({ name, isPacked }) {
let itemContent = name;
if (isPacked) {
- itemContent = name + " ✔";
+ itemContent = name + ' ✔';
}
return (
@@ -369,19 +369,19 @@ function Item({ name, isPacked }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -391,7 +391,7 @@ export default function PackingList() {
-Like before, this works not only for text, but for arbitrary JSX too:
+Как и раньше, это работает не только для текста, но и для произвольного JSX:
@@ -415,19 +415,19 @@ function Item({ name, isPacked }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -437,16 +437,16 @@ export default function PackingList() {
-If you're not familiar with JavaScript, this variety of styles might seem overwhelming at first. However, learning them will help you read and write any JavaScript code -- and not just React components! Pick the one you prefer for a start, and then consult this reference again if you forget how the other ones work.
+Если вы не знакомы с JavaScript, то такое разнообразие стилей может показаться поначалу ошеломляющим. Однако их изучение поможет вам читать и писать любой JavaScript код, а не только React-компоненты! Выберите тот, который вам больше нравится, и при необходимости обратитесь к этому справочнику, если вы забудете, как работают другие.
-* In React, you control branching logic with JavaScript.
-* You can return a JSX expression conditionally with an `if` statement.
-* You can conditionally save some JSX to a variable and then include it inside other JSX by using the curly braces.
-* In JSX, `{cond ? : }` means *"if `cond`, render ``, otherwise ``"*.
-* In JSX, `{cond && }` means *"if `cond`, render ``, otherwise nothing"*.
-* The shortcuts are common, but you don't have to use them if you prefer plain `if`.
+- В React вы управляете логикой ветвления с помощью JavaScript.
+- Вы можете условно возвращать JSX-выражение с помощью оператора `if`.
+- Вы можете условно сохранить JSX в переменную и затем включить её в другой JSX с помощью фигурных скобок.
+- В JSX выражение `{cond ? : }` означает *"если `cond`, то отрендерить ``, иначе ``"*.
+- В JSX выражение `{cond && }` означает *"если `cond`, то отрендерить``, иначе ничего"*.
+- Эти сокращения являются общепринятыми, но эти сокращения необязательно использовать, если вы предпочитаете простой `if`.
@@ -454,9 +454,9 @@ If you're not familiar with JavaScript, this variety of styles might seem overwh
-#### Show an icon for incomplete items with `? :` {/*show-an-icon-for-incomplete-items-with--*/}
+#### Показать иконку для неупакованных вещей с `? :` {/*show-an-icon-for-incomplete-items-with--*/}
-Use the conditional operator (`cond ? a : b`) to render a ❌ if `isPacked` isn’t `true`.
+Используйте тернарный оператор (`cond ? a : b`), чтобы отрендерить❌, если `isPacked` не равен `true`.
@@ -472,19 +472,19 @@ function Item({ name, isPacked }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -510,19 +510,19 @@ function Item({ name, isPacked }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -534,15 +534,15 @@ export default function PackingList() {
-#### Show the item importance with `&&` {/*show-the-item-importance-with-*/}
+#### Показать важность вещи с помощью `&&` {/*show-the-item-importance-with-*/}
-In this example, each `Item` receives a numerical `importance` prop. Use the `&&` operator to render "_(Importance: X)_" in italics, but only for items that have non-zero importance. Your item list should end up looking like this:
+В этом примере каждый `Item` получает числовой проп `importance`. Используйте `&&`, чтобы рендерить "_(Важность: X)_" курсивом только для вещей с ненулевой важностью. Ваш список вещей должен выглядеть следующем образом:
-* Space suit _(Importance: 9)_
-* Helmet with a golden leaf
-* Photo of Tam _(Importance: 6)_
+- Космический скафандр _(Важность: 9)_
+- Шлем с золотым листом
+- Фотография Тэма _(Важность: 6)_
-Don't forget to add a space between the two labels!
+Не забудьте добавить пробел между двумя метками!
@@ -558,19 +558,19 @@ function Item({ name, importance }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -582,7 +582,7 @@ export default function PackingList() {
-This should do the trick:
+Это должно сработать:
@@ -593,7 +593,7 @@ function Item({ name, importance }) {
{name}
{importance > 0 && ' '}
{importance > 0 &&
- (Importance: {importance})
+ (Важность: {importance})
}
);
@@ -602,19 +602,19 @@ function Item({ name, importance }) {
export default function PackingList() {
return (
-
Sally Ride's Packing List
+
Список вещей Салли Райд
@@ -624,15 +624,15 @@ export default function PackingList() {
-Note that you must write `importance > 0 && ...` rather than `importance && ...` so that if the `importance` is `0`, `0` isn't rendered as the result!
+Помните, что вы должны писать `importance > 0 && ...` вместо `importance && ...`, чтобы при `importance` равном `0` число `0` не рендерилось в результате!
-In this solution, two separate conditions are used to insert a space between the name and the importance label. Alternatively, you could use a fragment with a leading space: `importance > 0 && <> ...>` or add a space immediately inside the ``: `importance > 0 && ...`.
+В этом решении используются два отдельных условия для вставки пробела между именем и меткой важности. Кроме того, можно использовать фрагмент с ведущим пробелом: `importance > 0 && <> ...>` или добавить пробел сразу внутри тега ``: `importance > 0 && ...`.
-#### Refactor a series of `? :` to `if` and variables {/*refactor-a-series-of---to-if-and-variables*/}
+#### Перепишите тернарный оператор `? :` на `if` и переменные {/*refactor-a-series-of---to-if-and-variables*/}
-This `Drink` component uses a series of `? :` conditions to show different information depending on whether the `name` prop is `"tea"` or `"coffee"`. The problem is that the information about each drink is spread across multiple conditions. Refactor this code to use a single `if` statement instead of three `? :` conditions.
+Компонент `Drink` использует серию условий `? :` для отображения разной информацию в зависимости от пропа `name` (может быть `"tea"` или `"coffee"`). Проблема заключается в том, что информация о каждом напитке разбросана по нескольким условиям. Перепишите этот код так, используя один `if` вместо трёх условий `? :`.
@@ -642,12 +642,12 @@ function Drink({ name }) {
);
@@ -665,11 +665,11 @@ export default function DrinkList() {
-Once you've refactored the code to use `if`, do you have further ideas on how to simplify it?
+После рефакторинга кода с использованием `if`, у вас есть ещё идеи о том, как упростить его?
-There are multiple ways you could go about this, but here is one starting point:
+Есть несколько способов, но вот один из них, с которого можно начать:
@@ -678,22 +678,22 @@ function Drink({ name }) {
let part, caffeine, age;
if (name === 'tea') {
part = 'leaf';
- caffeine = '15–70 mg/cup';
- age = '4,000+ years';
+ caffeine = '15–70 мг/чашка';
+ age = '4,000+ лет';
} else if (name === 'coffee') {
part = 'bean';
- caffeine = '80–185 mg/cup';
- age = '1,000+ years';
+ caffeine = '80–185 мг/чашка';
+ age = '1,000+ лет';
}
return (
{name}
-
Part of plant
+
Часть растения
{part}
-
Caffeine content
+
Содержание кофеина
{caffeine}
-
Age
+
Возраст
{age}
@@ -712,9 +712,9 @@ export default function DrinkList() {
-Here the information about each drink is grouped together instead of being spread across multiple conditions. This makes it easier to add more drinks in the future.
+Здесь информация о каждом напитке сгруппирована вместе, а не разбросана по нескольким условиям. Это облегчает добавление новых напитков в будущем.
-Another solution would be to remove the condition altogether by moving the information into objects:
+Другим решением будет удалить условия, переместив информацию в объекты:
@@ -722,14 +722,14 @@ Another solution would be to remove the condition altogether by moving the infor
const drinks = {
tea: {
part: 'leaf',
- caffeine: '15–70 mg/cup',
- age: '4,000+ years'
+ caffeine: '15–70 мг/чашка',
+ age: '4,000+ лет',
},
coffee: {
part: 'bean',
- caffeine: '80–185 mg/cup',
- age: '1,000+ years'
- }
+ caffeine: '80–185 мг/чашка',
+ age: '1,000+ лет',
+ },
};
function Drink({ name }) {
@@ -738,11 +738,11 @@ function Drink({ name }) {
{name}
-
Part of plant
+
Часть растения
{info.part}
-
Caffeine content
+
Содержание кофеина
{info.caffeine}
-
Age
+
Возраст
{info.age}
diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md
index f8f55605c..71cb93782 100644
--- a/src/content/learn/importing-and-exporting-components.md
+++ b/src/content/learn/importing-and-exporting-components.md
@@ -1,26 +1,26 @@
---
-title: Importing and Exporting Components
+title: Импорт и экспорт компонентов
---
-The magic of components lies in their reusability: you can create components that are composed of other components. But as you nest more and more components, it often makes sense to start splitting them into different files. This lets you keep your files easy to scan and reuse components in more places.
+«Магия» компонентов заключается в возможности их повторного использования: можно создавать компоненты, которые состоят из других компонентов. Но по мере увеличения их вложенности зачастую бывает разумным начать раскладывать их по разным файлам. Так навигация по ним останется простой, а компоненты станет легче использовать повторно.
-* What a root component file is
-* How to import and export a component
-* When to use default and named imports and exports
-* How to import and export multiple components from one file
-* How to split components into multiple files
+* Что такое корневой компонент
+* Как импортировать и экспортировать компонент
+* Когда использовать дефолтные и именованные импорты и экспорты
+* Как импортировать и экспортировать несколько компонентов из одного файла
+* Как разделять код компонентов на отдельные файлы
-## The root component file {/*the-root-component-file*/}
+## Файл корневого компонента {/*the-root-component-file*/}
-In [Your First Component](/learn/your-first-component), you made a `Profile` component and a `Gallery` component that renders it:
+В разделе [Ваш первый компонент](/learn/your-first-component) вы создали компонент `Profile` и компонент `Gallery`, который рендерит его:
@@ -29,7 +29,7 @@ function Profile() {
return (
);
}
@@ -37,7 +37,7 @@ function Profile() {
export default function Gallery() {
return (
-
Amazing scientists
+
Восхитительные ученые
@@ -52,17 +52,17 @@ img { margin: 0 10px 10px 0; height: 90px; }
-These currently live in a **root component file,** named `App.js` in this example. In [Create React App](https://create-react-app.dev/), your app lives in `src/App.js`. Depending on your setup, your root component could be in another file, though. If you use a framework with file-based routing, such as Next.js, your root component will be different for every page.
+Эти компоненты сейчас находятся внутри **файла корневого компонента,** который в примере называется `App.js`. При использовании [Create React App](https://create-react-app.dev/) приложение находится в `src/App.js`. Однако, в зависимости от конфигурации проекта, корневой компонент может находиться в другом файле. У фреймворка с маршрутизацией на основе файлов, например Next.js, корневой компонент будет разным для каждой страницы.
-## Exporting and importing a component {/*exporting-and-importing-a-component*/}
+## Экспорт и импорт компонентов {/*exporting-and-importing-a-component*/}
-What if you want to change the landing screen in the future and put a list of science books there? Or place all the profiles somewhere else? It makes sense to move `Gallery` and `Profile` out of the root component file. This will make them more modular and reusable in other files. You can move a component in three steps:
+Что, если вы захотите изменить страницу и отобразить на ней список научных книг? Или переместить все профили ученых? Кажется разумным извлечь компоненты `Gallery` и `Profile` из файла корневого компонента. Это сделает их более модульными и переиспользуемыми. Переместить компонент можно за три шага:
-1. **Make** a new JS file to put the components in.
-2. **Export** your function component from that file (using either [default](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export) or [named](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_named_exports) exports).
-3. **Import** it in the file where you’ll use the component (using the corresponding technique for importing [default](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#importing_defaults) or [named](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#import_a_single_export_from_a_module) exports).
+1. **Создайте** новый JS файл для компонентов.
+2. **Экспортируйте** функциональный компонент из этого файла (используя или [экспорт по умолчанию](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export) или [именованный](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_named_exports) экспорт).
+3. **Импортируйте** компонент в файл, где вы будете его использовать (используя соответствующую технику для импорта значения [по умолчанию](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#importing_defaults) или [именованного](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#import_a_single_export_from_a_module) экспорта).
-Here both `Profile` and `Gallery` have been moved out of `App.js` into a new file called `Gallery.js`. Now you can change `App.js` to import `Gallery` from `Gallery.js`:
+В следующем примере `Profile` и `Gallery` были извлечены из `App.js` в новый файл `Gallery.js`. Теперь вы можете изменить `App.js`, добавив в него импорт компонента `Gallery` из файла `Gallery.js`:
@@ -81,7 +81,7 @@ function Profile() {
return (
);
}
@@ -89,7 +89,7 @@ function Profile() {
export default function Gallery() {
return (
-
Amazing scientists
+
Восхитительные ученые
@@ -104,60 +104,61 @@ img { margin: 0 10px 10px 0; height: 90px; }
-Notice how this example is broken down into two component files now:
+Обратите внимание, что код из примера теперь использует два файла компонентов:
1. `Gallery.js`:
- - Defines the `Profile` component which is only used within the same file and is not exported.
- - Exports the `Gallery` component as a **default export.**
+ - Содержит компонент `Profile`, который используется только в этом файле и не экспортируется.
+ - Экспортирует компонент `Gallery` **по умолчанию.**
2. `App.js`:
- - Imports `Gallery` as a **default import** from `Gallery.js`.
- - Exports the root `App` component as a **default export.**
+ - Импортирует компонент `Gallery` из `Gallery.js` **по умолчанию.**
+ - Экспортирует корневой компонент `App` **по умолчанию.**
-You may encounter files that leave off the `.js` file extension like so:
+В некоторых случаях вы можете заметить, что при импорте в именах файлов опускается расширение `.js`, например:
```js
import Gallery from './Gallery';
```
-Either `'./Gallery.js'` or `'./Gallery'` will work with React, though the former is closer to how [native ES Modules](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules) work.
+Оба варианта (`'./Gallery.js'` и `'./Gallery'`) будут работать в React, хотя первый вариант ближе к тому, как работают [нативные ES-модули](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules).
-#### Default vs named exports {/*default-vs-named-exports*/}
+#### Экспорт по умолчанию и именованный экспорт {/*default-vs-named-exports*/}
-There are two primary ways to export values with JavaScript: default exports and named exports. So far, our examples have only used default exports. But you can use one or both of them in the same file. **A file can have no more than one _default_ export, but it can have as many _named_ exports as you like.**
+Существует два основных способа экспорта значений в JavaScript: экспорт по умолчанию и именованный экспорт. До сих пор в примерах использовался только экспорт по умолчанию. Но вы можете использовать один из этих способов или оба в одном файле. **В файле не может быть больше одного экспорта _по умолчанию_, но сколько угодно _именованных_ экспортов.**
-![Default and named exports](/images/docs/illustrations/i_import-export.svg)
+![Именованные экспорты и экспорты по умолчанию](/images/docs/illustrations/i_import-export.svg)
-How you export your component dictates how you must import it. You will get an error if you try to import a default export the same way you would a named export! This chart can help you keep track:
+Способ, которым компонент был экспортирован, определяет способ, которым его нужно импортировать. Вы получите ошибку, если попытаетесь импортировать экспортированный по умолчанию компонент так же, как компонент с именованным экспортом! Эта таблица поможет вам разобраться:
-| Syntax | Export statement | Import statement |
+| Синтаксис экспорта | Как экспортировать | Как импортировать |
| ----------- | ----------- | ----------- |
-| Default | `export default function Button() {}` | `import Button from './Button.js';` |
-| Named | `export function Button() {}` | `import { Button } from './Button.js';` |
+| По умолчанию | `export default function Button() {}` | `import Button from './Button.js';` |
+| Именованный | `export function Button() {}` | `import { Button } from './Button.js';` |
-When you write a _default_ import, you can put any name you want after `import`. For example, you could write `import Banana from './Button.js'` instead and it would still provide you with the same default export. In contrast, with named imports, the name has to match on both sides. That's why they are called _named_ imports!
+При использовании импорта _по умолчанию_ можно использовать любое имя после слова `import`. Например, можно написать `import Banana from './Button.js'`, и эта запись все еще будет корректно импортировать значение по умолчанию. При использовании именованных импортов, напротив, значения должны совпадать в обоих файлах. Именно поэтому такие импорты называются _именованными_.
+
+**Разработчики часто используют экспорт по умолчанию, если файл экспортирует только один компонент, и именованный экспорт, если он экспортирует несколько компонентов и значений.** Независимо от того, какой стиль написания кода вы предпочитаете, всегда давайте осмысленные имена вашим функциональным компонентам и файлам, которые их содержат. Не рекомендуется использовать компоненты без имен, такие как `export default () => {}`, поскольку это затрудняет отладку.
-**People often use default exports if the file exports only one component, and use named exports if it exports multiple components and values.** Regardless of which coding style you prefer, always give meaningful names to your component functions and the files that contain them. Components without names, like `export default () => {}`, are discouraged because they make debugging harder.
-## Exporting and importing multiple components from the same file {/*exporting-and-importing-multiple-components-from-the-same-file*/}
+## Экспорт и импорт нескольких компонентов из одного файла {/*exporting-and-importing-multiple-components-from-the-same-file*/}
-What if you want to show just one `Profile` instead of a gallery? You can export the `Profile` component, too. But `Gallery.js` already has a *default* export, and you can't have _two_ default exports. You could create a new file with a default export, or you could add a *named* export for `Profile`. **A file can only have one default export, but it can have numerous named exports!**
+Что, если вы хотите показывать только один компонент `Profile` вместо всей галереи? Компонент `Profile` тоже можно экспортировать. Но в файле `Gallery.js` уже есть экспорт *по умолчанию*, а в одном файле не может быть _двух_ экспортов по умолчанию. Вы можете создать новый файл с экспортом по умолчанию или добавить *именованный* экспорт для компонента `Profile`. **В файле может быть только один экспорт по умолчанию, но несколько именованных экспортов!**
-To reduce the potential confusion between default and named exports, some teams choose to only stick to one style (default or named), or avoid mixing them in a single file. Do what works best for you!
+Чтобы избежать потенциальной путаницы между дефолтными и именованными экспортами, некоторые команды предпочитают придерживаться только одного стиля (экспорт по умолчанию или именованный) или не смешивать их в одном файле. Делайте то, что подходит именно вам!
-First, **export** `Profile` from `Gallery.js` using a named export (no `default` keyword):
+Сначала **экспортируйте** `Profile` из `Gallery.js`, используя именованный экспорт (без использования ключевого слова `default`):
```js
export function Profile() {
@@ -165,13 +166,13 @@ export function Profile() {
}
```
-Then, **import** `Profile` from `Gallery.js` to `App.js` using a named import (with the curly braces):
+Затем **импортируйте** `Profile` из `Gallery.js` в `App.js`, используя именованный импорт (с фигурными скобками):
```js
import { Profile } from './Gallery.js';
```
-Finally, **render** `` from the `App` component:
+Теперь вы можете **отрендерить** `` из компонента `App`:
```js
export default function App() {
@@ -179,8 +180,7 @@ export default function App() {
}
```
-Now `Gallery.js` contains two exports: a default `Gallery` export, and a named `Profile` export. `App.js` imports both of them. Try editing `` to `` and back in this example:
-
+Теперь `Gallery.js` содержит два экспорта: экспорт по умолчанию `Gallery` и именованный экспорт `Profile`. `App.js` импортирует их оба. Попробуйте изменить `` на `` и обратно в этом примере:
```js App.js
@@ -199,7 +199,7 @@ export function Profile() {
return (
);
}
@@ -207,7 +207,7 @@ export function Profile() {
export default function Gallery() {
return (
-
Amazing scientists
+
Восхитительные ученые
@@ -222,24 +222,24 @@ img { margin: 0 10px 10px 0; height: 90px; }
-Now you're using a mix of default and named exports:
+Теперь вы используете как именованные экспорты, так и экспорты по умолчанию:
* `Gallery.js`:
- - Exports the `Profile` component as a **named export called `Profile`.**
- - Exports the `Gallery` component as a **default export.**
+ - Экспортирует компонент `Profile` как **именованный экспорт `Profile`.**
+ - Экспортирует компонент `Gallery` **по умолчанию.**
* `App.js`:
- - Imports `Profile` as a **named import called `Profile`** from `Gallery.js`.
- - Imports `Gallery` as a **default import** from `Gallery.js`.
- - Exports the root `App` component as a **default export.**
+ - Импортирует компонент `Profile` как **именованный импорт `Profile`** из файла `Gallery.js`.
+ - Импортирует компонент `Gallery` как **экспорт по умолчанию** из файла `Gallery.js`.
+ - Экспортирует корневой компонент `App` **по умолчанию.**
-On this page you learned:
+В этом разделе вы узнали:
-* What a root component file is
-* How to import and export a component
-* When and how to use default and named imports and exports
-* How to export multiple components from the same file
+* Что такое корневой компонент
+* Как импортировать и экспортировать компонент
+* Когда использовать дефолтные и именованные импорты и экспорты
+* Как экспортировать несколько компонентов из одного файла
@@ -247,23 +247,22 @@ On this page you learned:
-#### Split the components further {/*split-the-components-further*/}
+#### Дальнейшее разделение компонентов {/*split-the-components-further*/}
-Currently, `Gallery.js` exports both `Profile` and `Gallery`, which is a bit confusing.
+Сейчас файл `Gallery.js` экспортирует два компонента (`Profile` и `Gallery`), что может немного сбивать с толку.
-Move the `Profile` component to its own `Profile.js`, and then change the `App` component to render both `` and `` one after another.
+Переместите компонент `Profile` в отдельный файл `Profile.js`, и затем изменить компонент `App` так, чтобы в нем друг за другом рендерились компоненты `` и ``.
-You may use either a default or a named export for `Profile`, but make sure that you use the corresponding import syntax in both `App.js` and `Gallery.js`! You can refer to the table from the deep dive above:
+Вы можете использовать либо экспорт по умолчанию, либо именованный экспорт для `Profile`, но убедитесь, что вы используете соответствующий синтаксис импорта как в `App.js`, так и в `Gallery.js`! Вы можете свериться с этой таблицей:
-| Syntax | Export statement | Import statement |
+| Синтаксис экспорта | Как экспортировать | Как импортировать |
| ----------- | ----------- | ----------- |
-| Default | `export default function Button() {}` | `import Button from './Button.js';` |
-| Named | `export function Button() {}` | `import { Button } from './Button.js';` |
+| По умолчанию | `export default function Button() {}` | `import Button from './Button.js';` |
+| Именованный | `export function Button() {}` | `import { Button } from './Button.js';` |
-Don't forget to import your components where they are called. Doesn't `Gallery` use `Profile`, too?
-
+Не забывайте импортировать компоненты там, где они используются. `Gallery` тоже использует `Profile`, не так ли?
@@ -282,12 +281,12 @@ export default function App() {
```
```js Gallery.js active
-// Move me to Profile.js!
+// Перемести меня в Profile.js!
export function Profile() {
return (
);
}
@@ -295,7 +294,7 @@ export function Profile() {
export default function Gallery() {
return (
-
Amazing scientists
+
Восхитительные ученые
@@ -313,12 +312,11 @@ img { margin: 0 10px 10px 0; height: 90px; }
-After you get it working with one kind of exports, make it work with the other kind.
+После того, как вы выполните это задание с использованием одного из типов экспорта, выполните его с использованием другого типа.
-This is the solution with named exports:
-
+Вот решение, использующее именованные экспорты:
```js App.js
@@ -341,7 +339,7 @@ import { Profile } from './Profile.js';
export default function Gallery() {
return (
-
Amazing scientists
+
Восхитительные ученые
@@ -355,7 +353,7 @@ export function Profile() {
return (
);
}
@@ -367,7 +365,7 @@ img { margin: 0 10px 10px 0; height: 90px; }
-This is the solution with default exports:
+Вот решение, использующее экспорты по умолчанию:
@@ -391,7 +389,7 @@ import Profile from './Profile.js';
export default function Gallery() {
return (
-
Amazing scientists
+
Восхитительные ученые
@@ -405,7 +403,7 @@ export default function Profile() {
return (
);
}
diff --git a/src/content/learn/index.md b/src/content/learn/index.md
index b57655bc4..d1d8f83de 100644
--- a/src/content/learn/index.md
+++ b/src/content/learn/index.md
@@ -4,51 +4,51 @@ title: Quick Start
-Welcome to the React documentation! This page will give you an introduction to the 80% of React concepts that you will use on a daily basis.
+Добро пожаловать в документацию React! Эта страница познакомит вас с большинством концепций React, которыми вы будете пользоваться каждый день.
-- How to create and nest components
-- How to add markup and styles
-- How to display data
-- How to render conditions and lists
-- How to respond to events and update the screen
-- How to share data between components
+- Как создавать и вкладывать компоненты
+- Как добавлять разметку и стили
+- Как отображать данные
+- Как отрисовывать условия и списки
+- Как реагировать на события и обновлять страницу
+- Как обмениваться данными между компонентами
-## Creating and nesting components {/*components*/}
+## Создание и вложение компонентов {/*components*/}
-React apps are made out of *components*. A component is a piece of the UI (user interface) that has its own logic and appearance. A component can be as small as a button, or as large as an entire page.
+Приложения на React собираются из *компонентов*. Компонент — это часть пользовательского интерфейса, у которого есть собственная логика и внешность. Компонент может быть маленьким, как кнопка, или большим, как целая страница.
-React components are JavaScript functions that return markup:
+React-компоненты — это функции JavaScript, которые возвращают разметку:
```js
function MyButton() {
return (
-
+
);
}
```
-Now that you've declared `MyButton`, you can nest it into another component:
+Вы объявили компонент `MyButton`, который можно вложить в другой компонент:
```js {5}
export default function MyApp() {
return (
-
Welcome to my app
+
Добро пожаловать в моё приложение
);
}
```
-Notice that `` starts with a capital letter. That's how you know it's a React component. React component names must always start with a capital letter, while HTML tags must be lowercase.
+Обратите внимание на то, что `` начинается с заглавной буквы. Это отличительная черта компонентов React. Названия компонентов в React всегда должны начинаться с заглавной буквы, а теги HTML — с маленькой.
-Have a look at the result:
+Посмотрите на результат:
@@ -56,7 +56,7 @@ Have a look at the result:
function MyButton() {
return (
);
}
@@ -64,7 +64,7 @@ function MyButton() {
export default function MyApp() {
return (
-
Welcome to my app
+
Добро пожаловать в моё приложение
);
@@ -73,49 +73,49 @@ export default function MyApp() {
-The `export default` keywords specify the main component in the file. If you're not familiar with some piece of JavaScript syntax, [MDN](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) and [javascript.info](https://javascript.info/import-export) have great references.
+Ключевые слова `export default` указывают на основной компонент в файле. Для того, чтобы понять некоторые особенности синтаксиса JavaScript, можно пользоваться ресурсами [MDN](https://developer.mozilla.org/ru-RU/docs/web/javascript/reference/statements/export) и [learn.javascript.ru](https://learn.javascript.ru/import-export).
-## Writing markup with JSX {/*writing-markup-with-jsx*/}
+## Написание разметки с JSX {/*writing-markup-with-jsx*/}
-The markup syntax you've seen above is called *JSX*. It is optional, but most React projects use JSX for its convenience. All of the [tools we recommend for local development](/learn/installation) support JSX out of the box.
+Синтаксис разметки, который вы видели выше, называется *JSX*. Он не обязателен, но большинство проектов на React предпочитают его использовать из-за удобства. Все [инструменты, которые мы рекомендуем для локальной разработки,](/learn/installation) поддерживают JSX.
-JSX is stricter than HTML. You have to close tags like ` `. Your component also can't return multiple JSX tags. You have to wrap them into a shared parent, like a `
...
` or an empty `<>...>` wrapper:
+JSX строже HTML. Вам нужно закрывать теги вроде ` `. Ваш компонент также не может возвращать несколько JSX-тегов. Их нужно будет обернуть внутрь общего родителя, например, `
...
` или пустую обёртку вида `<>...>`:
```js {3,6}
function AboutPage() {
return (
<>
-
About
-
Hello there. How do you do?
+
Обо мне
+
Привет. Как дела?
>
);
}
```
-If you have a lot of HTML to port to JSX, you can use an [online converter.](https://transform.tools/html-to-jsx)
+Для того, чтобы перевести большое количество HTML-верстки в JSX, можно использовать [онлайн-конвертер.](https://transform.tools/html-to-jsx)
-## Adding styles {/*adding-styles*/}
+## Добавление стилей {/*adding-styles*/}
-In React, you specify a CSS class with `className`. It works the same way as the HTML [`class`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class) attribute:
+В React CSS-классы объявляются с помощью `className`. Оно работает аналогично HTML-атрибуту [`class`](https://developer.mozilla.org/ru-RU/docs/Web/HTML/Global_attributes/class):
```js
```
-Then you write the CSS rules for it in a separate CSS file:
+В отдельном CSS-файле вы пишете для него CSS-правила:
```css
-/* In your CSS */
+/* В вашем CSS */
.avatar {
border-radius: 50%;
}
```
-React does not prescribe how you add CSS files. In the simplest case, you'll add a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) tag to your HTML. If you use a build tool or a framework, consult its documentation to learn how to add a CSS file to your project.
+React не ограничивает вас в том, как добавлять CSS-файлы. В самом простом случае вы добавите тег [``](https://developer.mozilla.org/ru-RU/docs/Web/HTML/Element/link) в ваш HTML-файл. Если вы используете инструмент для сборки или фреймворк, обратитесь к его документации, чтобы понять, как добавить CSS-файл в ваш проект.
-## Displaying data {/*displaying-data*/}
+## Отображение данных {/*displaying-data*/}
-JSX lets you put markup into JavaScript. Curly braces let you "escape back" into JavaScript so that you can embed some variable from your code and display it to the user. For example, this will display `user.name`:
+Фигурные скобки внутри JSX-разметки позволяют использовать JavaScript, например, для того, чтобы отобразить свою переменную пользователю. Код ниже отобразит `user.name`:
```js {3}
return (
@@ -125,7 +125,7 @@ return (
);
```
-You can also "escape into JavaScript" from JSX attributes, but you have to use curly braces *instead of* quotes. For example, `className="avatar"` passes the `"avatar"` string as the CSS class, but `src={user.imageUrl}` reads the JavaScript `user.imageUrl` variable value, and then passes that value as the `src` attribute:
+Вы также можете использовать JavaScript в атрибутах JSX. В таком случае вам нужно поставить фигурные скобки *вместо* кавычек. Например, `className="avatar"` передаёт строку `"avatar"` как CSS-класс, а `src={user.imageUrl}` считывает значение JavaScript-переменной `user.imageUrl` и передаёт его в качестве атрибута `src`:
```js {3,4}
return (
@@ -136,7 +136,7 @@ return (
);
```
-You can put more complex expressions inside the JSX curly braces too, for example, [string concatenation](https://javascript.info/operators#string-concatenation-with-binary):
+Вы также можете использовать в JSX более сложные выражения внутри фигурных скобок, например, [сложение строк](https://learn.javascript.ru/operators#slozhenie-strok-pri-pomoschi-binarnogo):
@@ -154,7 +154,7 @@ export default function Profile() {
-In the above example, `style={{}}` is not a special syntax, but a regular `{}` object inside the `style={ }` JSX curly braces. You can use the `style` attribute when your styles depend on JavaScript variables.
+В этом примере `style={{}}` не является специальным синтаксисом, а представляет из себя обычный объект `{}` внутри фигурных скобок JSX `style={ }`. Вы можете использовать атрибут `style` в случаях, когда ваши стили зависят от переменных JavaScript.
-## Conditional rendering {/*conditional-rendering*/}
+## Условный рендеринг {/*conditional-rendering*/}
-In React, there is no special syntax for writing conditions. Instead, you'll use the same techniques as you use when writing regular JavaScript code. For example, you can use an [`if`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) statement to conditionally include JSX:
+В React не существует специального синтаксиса для описания условий, вместо этого можно использовать обычный код на JavaScript. Например, для условного рендеринга JSX-кода можно применять [`if`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Statements/if...else):
```js
let content;
@@ -197,7 +197,7 @@ return (
);
```
-If you prefer more compact code, you can use the [conditional `?` operator.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) Unlike `if`, it works inside JSX:
+Если вы предпочитаете писать более компактный код, используйте [условный оператор `?`.](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) В отличие от `if` его можно использовать в JSX:
```js
@@ -209,7 +209,7 @@ If you prefer more compact code, you can use the [conditional `?` operator.](htt
```
-When you don't need the `else` branch, you can also use a shorter [logical `&&` syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation):
+Когда вам не нужна ветка `else`, можно использовать более короткий [логический оператор `&&`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation):
```js
@@ -217,23 +217,23 @@ When you don't need the `else` branch, you can also use a shorter [logical `&&`
```
-All of these approaches also work for conditionally specifying attributes. If you're unfamiliar with some of this JavaScript syntax, you can start by always using `if...else`.
+Все эти способы подходят и для задания условий в атрибутах. Если вам не знакомы такие синтаксические конструкции JavaScript, вы можете начать с использования `if...else`.
-## Rendering lists {/*rendering-lists*/}
+## Рендеринг списков {/*rendering-lists*/}
-You will rely on JavaScript features like [`for` loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) and the [array `map()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) to render lists of components.
+Для отрисовки списков компонентов вам будет нужно использовать такие возможности JavaScript, как [цикл `for`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Statements/for) и [функция массива `map()`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
-For example, let's say you have an array of products:
+Например, представим, что у вас есть массив продуктов:
```js
const products = [
- { title: 'Cabbage', id: 1 },
- { title: 'Garlic', id: 2 },
- { title: 'Apple', id: 3 },
+ { title: 'Капуста', id: 1 },
+ { title: 'Чеснок', id: 2 },
+ { title: 'Яблоко', id: 3 },
];
```
-Inside your component, use the `map()` function to transform an array of products into an array of `
` items:
+Преобразуйте этот массив в массив элементов `
` с помощью функции `map()` внутри вашего компонента:
```js
const listItems = products.map(product =>
@@ -247,15 +247,15 @@ return (
);
```
-Notice how `
` has a `key` attribute. For each item in a list, you should pass a string or a number that uniquely identifies that item among its siblings. Usually, a key should be coming from your data, such as a database ID. React uses your keys to know what happened if you later insert, delete, or reorder the items.
+Обратите внимание, что у `
` есть атрибут `key`. Для каждого элемента списка вам нужно задавать ключ в виде строки или числа, который позволит однозначно отделить этот элемент от остальных в списке. Обычно этот ключ берется из ваших данных, например, это может быть идентификатор из базы данных. React использует эти ключи при добавлении, удалении или изменении порядка элементов.
```js
const products = [
- { title: 'Cabbage', isFruit: false, id: 1 },
- { title: 'Garlic', isFruit: false, id: 2 },
- { title: 'Apple', isFruit: true, id: 3 },
+ { title: 'Капуста', isFruit: false, id: 1 },
+ { title: 'Чеснок', isFruit: false, id: 2 },
+ { title: 'Яблоко', isFruit: true, id: 3 },
];
export default function ShoppingList() {
@@ -278,14 +278,14 @@ export default function ShoppingList() {
-## Responding to events {/*responding-to-events*/}
+## Обработка событий {/*responding-to-events*/}
-You can respond to events by declaring *event handler* functions inside your components:
+Вы можете реагировать на события, объявляя внутри ваших компонентов функции *обработчиков событий*:
```js {2-4,7}
function MyButton() {
function handleClick() {
- alert('You clicked me!');
+ alert('Вы нажали на меня!');
}
return (
@@ -296,19 +296,19 @@ function MyButton() {
}
```
-Notice how `onClick={handleClick}` has no parentheses at the end! Do not _call_ the event handler function: you only need to *pass it down*. React will call your event handler when the user clicks the button.
+Заметьте: у `onClick={handleClick}` нет скобок в конце! Не _вызывайте_ функцию обработчика событий: вам нужно просто её *передать*. React вызовет ваш обработчик событий, когда пользователь кликнет по кнопке.
-## Updating the screen {/*updating-the-screen*/}
+## Обновление экрана {/*updating-the-screen*/}
-Often, you'll want your component to "remember" some information and display it. For example, maybe you want to count the number of times a button is clicked. To do this, add *state* to your component.
+Вам может понадобиться, чтобы компонент «помнил» какую-то информацию и отображал её. Например, вы хотите посчитать сколько раз была нажата кнопка. Для этого добавьте *состояние* в ваш компонент.
-First, import [`useState`](/reference/react/useState) from React:
+Сначала импортируйте [`useState`](/reference/react/useState) из React:
```js
import { useState } from 'react';
```
-Now you can declare a *state variable* inside your component:
+Теперь можно объявить *переменную состояния* внутри вашего компонента:
```js
function MyButton() {
@@ -316,9 +316,9 @@ function MyButton() {
// ...
```
-You’ll get two things from `useState`: the current state (`count`), and the function that lets you update it (`setCount`). You can give them any names, but the convention is to write `[something, setSomething]`.
+`useState` вернет вам две вещи: текущее состояние (`count`) и функцию (`setCount`), которая обновляет его. Можно именовать их как вам угодно, но такого рода вещи принято называть `[something, setSomething]`.
-The first time the button is displayed, `count` will be `0` because you passed `0` to `useState()`. When you want to change state, call `setCount()` and pass the new value to it. Clicking this button will increment the counter:
+При первом показе кнопка `count` будет иметь значение `0`, потому что вы передали `0` в `useState()`. Для изменения состояния вызовите `setCount()` и передайте туда новое значение. Клик на эту кнопку будет увеличивать счётчик:
```js {5}
function MyButton() {
@@ -330,15 +330,15 @@ function MyButton() {
return (
);
}
```
-React will call your component function again. This time, `count` will be `1`. Then it will be `2`. And so on.
+React снова вызовет функцию вашего компонента. На этот раз `count` будет равно `1`, затем `2`, и так далее.
-If you render the same component multiple times, each will get its own state. Click each button separately:
+Если вы рендерите один и тот же компонент несколько раз, то у каждого из них будет своё состояние. Попробуйте покликать на каждую кнопку по отдельности:
@@ -348,7 +348,7 @@ import { useState } from 'react';
export default function MyApp() {
return (
-
Counters that update separately
+
Независимо обновляющиеся счётчики
@@ -364,7 +364,7 @@ function MyButton() {
return (
);
}
@@ -379,59 +379,59 @@ button {
-Notice how each button "remembers" its own `count` state and doesn't affect other buttons.
+Обратите внимание на то, как каждая кнопка "помнит" свое состояние `count` и не влияет на другие кнопки.
-## Using Hooks {/*using-hooks*/}
+## Использование хуков {/*using-hooks*/}
-Functions starting with `use` are called *Hooks*. `useState` is a built-in Hook provided by React. You can find other built-in Hooks in the [API reference.](/reference/react) You can also write your own Hooks by combining the existing ones.
+Функции, которые начинаются с `use`, называются *хуками*. `useState` — это встроенный хук в React. В [справочнике API](/reference/react) приводятся другие встроенные хуки. Также, вы можете писать свои собственные хуки, совмещая их с уже существующими.
-Hooks are more restrictive than other functions. You can only call Hooks *at the top* of your components (or other Hooks). If you want to use `useState` in a condition or a loop, extract a new component and put it there.
+У хуков больше ограничений, чем у других функций. Хуки могут вызываться только *в начале* ваших компонентов (или других хуков). Если вам нужен `useState` в условии или цикле, выделите новый компонент и используйте его там.
-## Sharing data between components {/*sharing-data-between-components*/}
+## Обмен данными между компонентами {/*sharing-data-between-components*/}
-In the previous example, each `MyButton` had its own independent `count`, and when each button was clicked, only the `count` for the button clicked changed:
+В предыдущем примере у каждого `MyButton` имеется своё собственное состояние `count`, и при клике на каждую кнопку обновление `count` происходило только у нажатой кнопки.
-
+
-Initially, each `MyButton`'s `count` state is `0`
+В начале у каждого `MyButton` состояние `count` равно `0`
-
+
-The first `MyButton` updates its `count` to `1`
+Первый компонент `MyButton` обновляет свой `count` значением `1`
-However, often you'll need components to *share data and always update together*.
+Однако, вы будете часто сталкиваться с ситуацией, когда вам будет нужно, чтобы компоненты *имели общие данные и всегда обновлялись вместе*.
-To make both `MyButton` components display the same `count` and update together, you need to move the state from the individual buttons "upwards" to the closest component containing all of them.
+Для того, чтобы оба компонента `MyButton` отображали одно и то же значение `count`, вам нужно перенести состояние из отдельных кнопок «выше», в ближайший компонент, содержащий эти компоненты.
-In this example, it is `MyApp`:
+В этом случае таким компонентом является `MyApp`:
-
+
-Initially, `MyApp`'s `count` state is `0` and is passed down to both children
+Сначала состояние `count` компонента `MyApp` равно `0` и передаётся обоим потомкам
-
+
-On click, `MyApp` updates its `count` state to `1` and passes it down to both children
+При клике `MyApp` обновляет своё состояние `count` на значение `1` и передаёт его вниз обоим потомкам
-Now when you click either button, the `count` in `MyApp` will change, which will change both of the counts in `MyButton`. Here's how you can express this in code.
+Теперь, когда вы нажимаете на любую из кнопок, `count` в `MyApp` будет менять своё значение, что в свою очередь повлечёт обновление счётчиков в обоих компонентах `MyButton`. Вот как это можно выразить в коде.
-First, *move the state up* from `MyButton` into `MyApp`:
+Сначала *переместите вверх состояние* из `MyButton` в `MyApp`:
```js {2-6,18}
export default function MyApp() {
@@ -443,7 +443,7 @@ export default function MyApp() {
return (
-
Counters that update separately
+
Независимо обновляющиеся счётчики
@@ -451,12 +451,12 @@ export default function MyApp() {
}
function MyButton() {
- // ... we're moving code from here ...
+ // ... мы перемещаем код отсюда ...
}
```
-Then, *pass the state down* from `MyApp` to each `MyButton`, together with the shared click handler. You can pass information to `MyButton` using the JSX curly braces, just like you previously did with built-in tags like ``:
+Затем *передайте состояние на уровень ниже* из `MyApp` каждому `MyButton` вместе с общим обработчиком клика. Можно передавать информацию в `MyButton` через фигурные скобки JSX таким же образом, как вы это делали со встроенными тегами наподобие ``:
```js {11-12}
export default function MyApp() {
@@ -468,7 +468,7 @@ export default function MyApp() {
return (
-
Counters that update together
+
Одновременно обновляющиеся счётчики
@@ -476,21 +476,21 @@ export default function MyApp() {
}
```
-The information you pass down like this is called _props_. Now the `MyApp` component contains the `count` state and the `handleClick` event handler, and *passes both of them down as props* to each of the buttons.
+Информация, которую вы передаёте таким образом, называется _пропсами_. Теперь у компонента `MyApp` есть состояние `count` и обработчик событий `handleClick`, *которые он передаёт в качестве пропсов* каждой кнопке-потомку.
-Finally, change `MyButton` to *read* the props you have passed from its parent component:
+Наконец, измените компонент `MyButton` так, чтобы он *считывал* пропсы, переданные от своего родителя:
```js {1,3}
function MyButton({ count, onClick }) {
return (
);
}
```
-When you click the button, the `onClick` handler fires. Each button's `onClick` prop was set to the `handleClick` function inside `MyApp`, so the code inside of it runs. That code calls `setCount(count + 1)`, incrementing the `count` state variable. The new `count` value is passed as a prop to each button, so they all show the new value. This is called "lifting state up". By moving state up, you've shared it between components.
+При нажатии на кнопку срабатывает обработчик `onClick`. Каждой кнопке в качестве значения пропа `onClick` задана функция `handleClick` из `MyApp`, поэтому выполняется соответствующий код. Этот код вызывает функцию `setCount(count + 1)`, увеличивая значение состояния `count`. Новое значение `count` передаётся каждой кнопке в качестве пропа, поэтому они все отображают новое значение. Это называется "подъёмом состояния вверх". Поднимая состояние вверх, вы делаете его общим для всех компонентов.
@@ -531,8 +531,8 @@ button {
-## Next Steps {/*next-steps*/}
+## Следующие шаги {/*next-steps*/}
-By now, you know the basics of how to write React code!
+Теперь вы знаете основы того, как писать код для React!
-Check out the [Tutorial](/learn/tutorial-tic-tac-toe) to put them into practice and build your first mini-app with React.
+Ознакомьтесь с [введением](/learn/tutorial-tic-tac-toe), в рамках которого вы сможете применить полученные знания и собрать своё первое мини-приложение на React.
diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md
index c5426ea94..9884a65f2 100644
--- a/src/content/learn/installation.md
+++ b/src/content/learn/installation.md
@@ -1,25 +1,25 @@
---
-title: Installation
+title: Установка
---
-React has been designed from the start for gradual adoption. You can use as little or as much React as you need. Whether you want to get a taste of React, add some interactivity to an HTML page, or start a complex React-powered app, this section will help you get started.
+React был спроектирован с самого начала с учётом постепенного внедрения. Вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна как при первом знакомстве с React, так и при создании простой динамической HTML-страницы или проектировании сложного React-приложения.
-* [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)
+* [Как создать новый React-проект](/learn/start-a-new-react-project)
+* [Как добавить React в существующий проект](/learn/add-react-to-an-existing-project)
+* [Как настроить редактор кода](/learn/editor-setup)
+* [Как установить React Developer Tools](/learn/react-developer-tools)
-## Try React {/*try-react*/}
+## Попробовать React {/*try-react*/}
-You don't need to install anything to play with React. Try editing this sandbox!
+Вам не нужно ничего устанавливать, чтобы попробовать React. Поредактируйте код в песочнице!
@@ -35,23 +35,23 @@ export default function App() {
-You can edit it directly or open it in a new tab by pressing the "Fork" button in the upper right corner.
+Вы можете редактировать прямо здесь или же открыть код в новой вкладке, нажав на кнопку "Форкнуть" в правом верхнем углу.
-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?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb)
+Такие песочницы есть на большинстве страниц React-документации. За пределами React-документации также есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb)
-### Try React locally {/*try-react-locally*/}
+### Попробовать React локально {/*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!
+Чтобы попробовать React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте её в своем текстовом редакторе и браузере!
-## Start a new React project {/*start-a-new-react-project*/}
+## Начать новый React-проект {/*start-a-new-react-project*/}
-If you want to build an app or a website fully with React, [start a new React project.](/learn/start-a-new-react-project)
+Если вы хотите создать приложение или сайт полностью на React — [создайте новый React-проект.](/learn/start-a-new-react-project)
-## Add React to an existing project {/*add-react-to-an-existing-project*/}
+## Добавить React в существующий проект {/*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)
+Если вы хотите попробовать React в существующем приложении или сайте — [добавьте React в существующий проект.](/learn/add-react-to-an-existing-project)
-## Next steps {/*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.
+Перейдите к [Введению в React](/learn) для ознакомления с самыми важными концепциями, которые вы будете встречать каждый день.
diff --git a/src/content/learn/manipulating-the-dom-with-refs.md b/src/content/learn/manipulating-the-dom-with-refs.md
index b5c193763..3e91a7694 100644
--- a/src/content/learn/manipulating-the-dom-with-refs.md
+++ b/src/content/learn/manipulating-the-dom-with-refs.md
@@ -31,7 +31,7 @@ Then, use it to declare a ref inside your component:
const myRef = useRef(null);
```
-Finally, pass it to the DOM node as the `ref` attribute:
+Finally, pass your ref as the `ref` attribute to the JSX tag for which you want to get the DOM node:
```js
diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md
index 89208a6bb..c554df9c6 100644
--- a/src/content/learn/react-developer-tools.md
+++ b/src/content/learn/react-developer-tools.md
@@ -4,30 +4,31 @@ title: React Developer Tools
-Use React Developer Tools to inspect React [components](/learn/your-first-component), edit [props](/learn/passing-props-to-a-component) and [state](/learn/state-a-components-memory), and identify performance problems.
+Используйте React Developer Tools для инспекции [компонентов](/learn/your-first-component) React, редактирования [пропсов](/learn/passing-props-to-a-component) и [состояния](/learn/state-a-components-memory), а также для выявления проблем с производительностью.
-* How to install React Developer Tools
+* Как установить React Developer Tools
-## Browser extension {/*browser-extension*/}
+## Расширение для браузера {/*browser-extension*/}
-The easiest way to debug websites built with React is to install the React Developer Tools browser extension. It is available for several popular browsers:
+Самым простым способом отладки сайтов, созданных с использованием React, является установка браузерного расширения React Developer Tools. Оно доступно для нескольких популярных браузеров.
-* [Install for **Chrome**](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)
-* [Install for **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/)
-* [Install for **Edge**](https://microsoftedge.microsoft.com/addons/detail/react-developer-tools/gpphkfbcpidddadnkolkpfckpihlkkil)
+* [Установить для **Chrome**](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ru)
+* [Установить для **Firefox**](https://addons.mozilla.org/ru/firefox/addon/react-devtools/)
+* [Установить для **Edge**](https://microsoftedge.microsoft.com/addons/detail/react-developer-tools/gpphkfbcpidddadnkolkpfckpihlkkil)
-Now, if you visit a website **built with React,** you will see the _Components_ and _Profiler_ panels.
+Если вы откроете сайт, созданный с использованием React, вы увидите панели _Components_ и _Profiler_.
-![React Developer Tools extension](/images/docs/react-devtools-extension.png)
+![Расширение React Developer Tools](/images/docs/react-devtools-extension.png)
+
+### Safari и другие браузеры {/*safari-and-other-browsers*/}
+Для других браузеров, таких как Safari, необходимо установить npm пакет [`react-devtools`](https://www.npmjs.com/package/react-devtools):
-### Safari and other browsers {/*safari-and-other-browsers*/}
-For other browsers (for example, Safari), install the [`react-devtools`](https://www.npmjs.com/package/react-devtools) npm package:
```bash
# Yarn
yarn global add react-devtools
@@ -36,26 +37,26 @@ yarn global add react-devtools
npm install -g react-devtools
```
-Next open the developer tools from the terminal:
+Затем откройте инструменты разработчика из терминала:
```bash
react-devtools
```
-Then connect your website by adding the following `
```
-Reload your website in the browser now to view it in developer tools.
+Перезагрузите ваш сайт, чтобы просмотреть его в инструментах разработчика.
![React Developer Tools standalone](/images/docs/react-devtools-standalone.png)
-## Mobile (React Native) {/*mobile-react-native*/}
-React Developer Tools can be used to inspect apps built with [React Native](https://reactnative.dev/) as well.
+## Мобильные устройства (React Native) {/*mobile-react-native*/}
+React Developer Tools также можно использовать для отладки приложений, созданных с помощью [React Native](https://reactnative.dev/).
+Самый простой способ использования React Developer Tools - установить их глобально:
-The easiest way to use React Developer Tools is to install it globally:
```bash
# Yarn
yarn global add react-devtools
@@ -64,13 +65,13 @@ yarn global add react-devtools
npm install -g react-devtools
```
-Next open the developer tools from the terminal.
+Откройте инструменты разработчика в терминале.
```bash
react-devtools
```
-It should connect to any local React Native app that's running.
+Он подключится к любому локальному приложению React Native, которое запущено.
-> Try reloading the app if developer tools doesn't connect after a few seconds.
+> Попробуйте перезагрузить приложение, если инструменты разработчика не подключатся через несколько секунд.
-[Learn more about debugging React Native.](https://reactnative.dev/docs/debugging)
+[Узнайте больше о отладке React Native.](https://reactnative.dev/docs/debugging)
diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md
index da5d864ab..77f337d88 100644
--- a/src/content/learn/referencing-values-with-refs.md
+++ b/src/content/learn/referencing-values-with-refs.md
@@ -1,49 +1,49 @@
---
-title: 'Referencing Values with Refs'
+title: 'Обращаемся к значением через рефы'
---
-When you want a component to "remember" some information, but you don't want that information to [trigger new renders](/learn/render-and-commit), you can use a *ref*.
+Для того, чтобы компонент «запомнил» какие-либо данные, но изменения этих данных не [вызывали новый рендер](/learn/render-and-commit), вы можете использовать *реф*.
-- How to add a ref to your component
-- How to update a ref's value
-- How refs are different from state
-- How to use refs safely
+- Как добавить реф в ваш компонент
+- Как обновить значение рефа
+- Отличие рефа от состояния
+- Как безопасно использовать рефы
-## Adding a ref to your component {/*adding-a-ref-to-your-component*/}
+## Добавляем реф в ваш компонент {/*adding-a-ref-to-your-component*/}
-You can add a ref to your component by importing the `useRef` Hook from React:
+Чтобы добавить реф в ваш компонент, импортируйте хук `useRef` из React:
```js
import { useRef } from 'react';
```
-Inside your component, call the `useRef` Hook and pass the initial value that you want to reference as the only argument. For example, here is a ref to the value `0`:
+Внутри компонента вызовите хук `useRef` и передайте аргумент, который будет являться начальным значением. Например, здесь значением реф является `0`:
```js
const ref = useRef(0);
```
-`useRef` returns an object like this:
+`useRef` возвращает следующий объект:
```js
-{
- current: 0 // The value you passed to useRef
+{
+ current: 0 // Значение, которое вы передали в useRef
}
```
-
+
-You can access the current value of that ref through the `ref.current` property. This value is intentionally mutable, meaning you can both read and write to it. It's like a secret pocket of your component that React doesn't track. (This is what makes it an "escape hatch" from React's one-way data flow--more on that below!)
+Получить доступ к значению рефа можно через свойство `ref.current`. Это значение намеренно является мутируемым, т.е. оно доступно как для чтения, так и для изменения. По сути, это как секретный карман, за которым React не следит. (Благодаря этому, реф является «лазейкой» в однонаправленном потоке данных React. Подробнее об этом ниже!)
-Here, a button will increment `ref.current` on every click:
+В примере ниже создадим кнопку, которая будет увеличивать `ref.current` на каждый клик:
@@ -68,20 +68,20 @@ export default function Counter() {
-The ref points to a number, but, like [state](/learn/state-a-components-memory), you could point to anything: a string, an object, or even a function. Unlike state, ref is a plain JavaScript object with the `current` property that you can read and modify.
+Здесь реф ссылается на число, но как и в случае с [состоянием](/learn/state-a-components-memory), вы можете ссылаться на что угодно: на строку, объект или даже на функцию. В отличии от состояния, реф—это обычный JavaScript-объект со свойством `current`, которое можно читать и изменять.
-Note that **the component doesn't re-render with every increment.** Like state, refs are retained by React between re-renders. However, setting state re-renders a component. Changing a ref does not!
+Имейте в виду, что **изменение реф не вызовет повторный рендер на каждое изменение.** Рефы будут сохраняться между повторными рендерами, как и состояние. Однако, обновление состояние вызывает новый рендер. А изменение рефа нет!
-## Example: building a stopwatch {/*example-building-a-stopwatch*/}
+## Пример: создадим секундомер {/*example-building-a-stopwatch*/}
-You can combine refs and state in a single component. For example, let's make a stopwatch that the user can start or stop by pressing a button. In order to display how much time has passed since the user pressed "Start", you will need to keep track of when the Start button was pressed and what the current time is. **This information is used for rendering, so you'll keep it in state:**
+Рефы и состояние можно использовать в одном компоненте. Например, создадим секундомер, который можно будет запускать и останавливать нажатием кнопки. Чтобы отобразить сколько времени прошло с момента клика «Start», нужно следить за моментом клика и за текущим временем. **Так как эти данные используются при рендере, их лучше хранить в состоянии:**
```js
const [startTime, setStartTime] = useState(null);
const [now, setNow] = useState(null);
```
-When the user presses "Start", you'll use [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval) in order to update the time every 10 milliseconds:
+Чтобы обновлять время каждые 10 миллисекунд, после того как пользователь нажимает «Start», будем использовать [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval):
@@ -93,12 +93,12 @@ export default function Stopwatch() {
const [now, setNow] = useState(null);
function handleStart() {
- // Start counting.
+ // Начинаем отсчёт.
setStartTime(Date.now());
setNow(Date.now());
setInterval(() => {
- // Update the current time every 10ms.
+ // Обновляем текущее время каждые 10мс.
setNow(Date.now());
}, 10);
}
@@ -121,7 +121,7 @@ export default function Stopwatch() {
-When the "Stop" button is pressed, you need to cancel the existing interval so that it stops updating the `now` state variable. You can do this by calling [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), but you need to give it the interval ID that was previously returned by the `setInterval` call when the user pressed Start. You need to keep the interval ID somewhere. **Since the interval ID is not used for rendering, you can keep it in a ref:**
+Когда нажата кнопка «Stop», нужно очистить текущий интервал, чтобы значение состояния `now` перестало обновляться. Для реализации можно использовать вызов[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), но интервалу нужно задать ID, которое возвращается при вызове `setInterval`, когда пользователь нажал «Start». ID интервала нужно где-то сохранить. **Поскольку ID интервала не используется для рендера, вы можете сохранить его в реф:**
@@ -168,20 +168,20 @@ export default function Stopwatch() {
-When a piece of information is used for rendering, keep it in state. When a piece of information is only needed by event handlers and changing it doesn't require a re-render, using a ref may be more efficient.
+Когда какие-то данные используются для рендера, держите её в состоянии. Когда данные нужны только для обработчиков событий, и изменение этих данных не требуют повторного рендера, использование реф будет более эффективным.
-## Differences between refs and state {/*differences-between-refs-and-state*/}
+## Отличие рефа от состояния {/*differences-between-refs-and-state*/}
-Perhaps you're thinking refs seem less "strict" than state—you can mutate them instead of always having to use a state setting function, for instance. But in most cases, you'll want to use state. Refs are an "escape hatch" you won't need often. Here's how state and refs compare:
+Может показаться, что рефы менее «строгие», чем состояние—их можно изменять напрямую, вместо использования функции для обновления состояния. Но в большинстве случаев вам захочется использовать состояние. Рефы—это «лазейка», которую не рекомендуется использовать слишком часто. Ниже сравнение рефа и состояния:
-| refs | state |
+| refs | state |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
-| `useRef(initialValue)` returns `{ current: initialValue }` | `useState(initialValue)` returns the current value of a state variable and a state setter function ( `[value, setValue]`) |
-| Doesn't trigger re-render when you change it. | Triggers re-render when you change it. |
-| Mutable—you can modify and update `current`'s value outside of the rendering process. | "Immutable"—you must use the state setting function to modify state variables to queue a re-render. |
-| You shouldn't read (or write) the `current` value during rendering. | You can read state at any time. However, each render has its own [snapshot](/learn/state-as-a-snapshot) of state which does not change.
+| `useRef(initialValue)` возвращает `{ current: initialValue }` | `useState(initialValue)` возвращает текущее значение состояния и функцию-сеттер для его обновления ( `[value, setValue]`) |
+| При изменении не вызывает повторный рендер. | При изменении вызывает повторный рендер. |
+| Мутабельный—можно изменять и обновлять значение `current` независимо от процесса рендера. | «Иммутабельный»—обязательно использовать функцию-сеттер, чтобы добавить изменение состояния в очередь обновлений. |
+| Не рекомендуется читать (или изменять) значение `current` во время рендера. | Можно читать значение состояния в любое время. Однако, за каждым рендером закреплён свой [снимок](/learn/state-as-a-snapshot) состояния, который не будет изменяться.
-Here is a counter button that's implemented with state:
+В следующем примере создадим кнопку счётчика, которая использует состояние:
@@ -205,9 +205,9 @@ export default function Counter() {
-Because the `count` value is displayed, it makes sense to use a state value for it. When the counter's value is set with `setCount()`, React re-renders the component and the screen updates to reflect the new count.
+В этом случае имеет смысл использовать состояние, т.к. значение `count` отображается на странице. Когда состояние счётчика обновляется при помощи `setCount()`, React вызывает повторный рендер и на экране отображается новое значение счётчика.
-If you tried to implement this with a ref, React would never re-render the component, so you'd never see the count change! See how clicking this button **does not update its text**:
+Если использовать реф, React никогда не вызовет повторный рендер, поэтому вы никогда не увидите изменение счётчика! Например, в данном случае клик по кнопке **не обновляет её текст**:
@@ -218,7 +218,7 @@ export default function Counter() {
let countRef = useRef(0);
function handleClick() {
- // This doesn't re-render the component!
+ // Повторный рендер не вызовется!
countRef.current = countRef.current + 1;
}
@@ -232,68 +232,68 @@ export default function Counter() {
-This is why reading `ref.current` during render leads to unreliable code. If you need that, use state instead.
+Именно поэтому чтение из `ref.current` во время рендера приводит к непредсказуемому результату. Используйте состояние, если во время рендера вам точно нужно читать данные из него!
-#### How does useRef work inside? {/*how-does-use-ref-work-inside*/}
+#### Как работает useRef изнутри? {/*how-does-use-ref-work-inside*/}
-Although both `useState` and `useRef` are provided by React, in principle `useRef` could be implemented _on top of_ `useState`. You can imagine that inside of React, `useRef` is implemented like this:
+Хотя оба хука `useState` и `useRef` могут быть импортированы из React, `useRef` может быть реализован поверх `useState`. Можно представлять, что внутри React `useRef` реализован следующим образом:
```js
-// Inside of React
+// Внутри React
function useRef(initialValue) {
const [ref, unused] = useState({ current: initialValue });
return ref;
}
```
-During the first render, `useRef` returns `{ current: initialValue }`. This object is stored by React, so during the next render the same object will be returned. Note how the state setter is unused in this example. It is unnecessary because `useRef` always needs to return the same object!
+Во время первого рендера `useRef` возвращает `{ current: initialValue }`. Этот объект сохраняется внутри React, поэтому во время следующего рендера вернётся точно такой же объект. Обратите внимание, что функция для обновления состояния в этом примере не используется. В этом нет необходимости, т.к. `useRef` всегда возвращает один и тот же объект!
-React provides a built-in version of `useRef` because it is common enough in practice. But you can think of it as a regular state variable without a setter. If you're familiar with object-oriented programming, refs might remind you of instance fields--but instead of `this.something` you write `somethingRef.current`.
+React предоставляет встроенный хук `useRef`, т.к. это достаточно часто встречается на практике. Но можно представлять себе, что это обычное значение состояния, но без функции обновления. Если вы знакомы с объектно-ориентированным программированием, рефы могут напоминать вам поля экземпляра--но вместо `this.something` используется `somethingRef.current`.
-## When to use refs {/*when-to-use-refs*/}
+## Когда использовать рефы {/*when-to-use-refs*/}
-Typically, you will use a ref when your component needs to "step outside" React and communicate with external APIs—often a browser API that won't impact the appearance of the component. Here are a few of these rare situations:
+Как правило, вы будете использовать реф, когда захотите выйти за пределы парадигмы React и иметь возможность взаимодействовать со сторонними API—часто это API браузера, которое никак не влияет на отображение компонента на странице. Ниже приведены примеры таких ситуаций:
-- Storing [timeout IDs](https://developer.mozilla.org/docs/Web/API/setTimeout)
-- Storing and manipulating [DOM elements](https://developer.mozilla.org/docs/Web/API/Element), which we cover on [the next page](/learn/manipulating-the-dom-with-refs)
-- Storing other objects that aren't necessary to calculate the JSX.
+- Хранение [ID таймера](https://developer.mozilla.org/docs/Web/API/setTimeout)
+- Хранение и манипулирование [DOM-элементами](https://developer.mozilla.org/docs/Web/API/Element), которое мы разберём [в следующей главе](/learn/manipulating-the-dom-with-refs)
+- Хранение различных других объектов, которые не влияют на JSX.
-If your component needs to store some value, but it doesn't impact the rendering logic, choose refs.
+Если вы хотите сохранить какое-то значение внутри компонента, которое не влияет на логику рендера, используйте реф.
-## Best practices for refs {/*best-practices-for-refs*/}
+## Рекомендации по использованию рефов {/*best-practices-for-refs*/}
-Following these principles will make your components more predictable:
+Следуйте следующим принципам, чтобы сделать ваши компоненты более предсказуемыми:
-- **Treat refs as an escape hatch.** Refs are useful when you work with external systems or browser APIs. If much of your application logic and data flow relies on refs, you might want to rethink your approach.
-- **Don't read or write `ref.current` during rendering.** If some information is needed during rendering, use [state](/learn/state-a-components-memory) instead. Since React doesn't know when `ref.current` changes, even reading it while rendering makes your component's behavior difficult to predict. (The only exception to this is code like `if (!ref.current) ref.current = new Thing()` which only sets the ref once during the first render.)
+- **Используйте рефы как лазейку.** Использование рефов является оправданным, когда вы работаете со сторонними системами или с API браузера. Если большая часть логики вашего приложения и потока данных зависит от рефов, скорее всего вам стоит переосмыслить свой подход.
+- **Не читайте и не изменяйте `ref.current` во время рендера.** Если необходимо использовать какие-то данные во время рендера, используйте [состояние](/learn/state-a-components-memory) вместо рефа. Даже просто чтение во время рендера делает поведение вашего компонента менее предсказуемым, поскольку React ничего не знает об изменении `ref.current`. (Единственным исключением является `if (!ref.current) ref.current = new Thing()`, где реф устанавливается единожды, во время первого рендера.)
-Limitations of React state don't apply to refs. For example, state acts like a [snapshot for every render](/learn/state-as-a-snapshot) and [doesn't update synchronously.](/learn/queueing-a-series-of-state-updates) But when you mutate the current value of a ref, it changes immediately:
+Ограничения React при использовании состояния никак не влияют на рефы. Например, состояние ведёт себя как [снимок для каждого рендера](/learn/state-as-a-snapshot) и [не обновляется синхронно.](/learn/queueing-a-series-of-state-updates) Но при изменении текущего значения реф, оно изменяется сразу же:
```js
ref.current = 5;
console.log(ref.current); // 5
```
-This is because **the ref itself is a regular JavaScript object,** and so it behaves like one.
+Это обусловлено тем, что **реф—это обычный JavaScript-объект,** и ведёт себя как объект.
-You also don't need to worry about [avoiding mutation](/learn/updating-objects-in-state) when you work with a ref. As long as the object you're mutating isn't used for rendering, React doesn't care what you do with the ref or its contents.
+Когда вы работаете с рефами, вам не нужно беспокоится о том, чтобы [избегать мутаций](/learn/updating-objects-in-state). До тех пор пока объект, который вы мутируете не используется для рендера, React нет дела, что вы делаете с рефами и их значениями.
-## Refs and the DOM {/*refs-and-the-dom*/}
+## Рефы и DOM {/*refs-and-the-dom*/}
-You can point a ref to any value. However, the most common use case for a ref is to access a DOM element. For example, this is handy if you want to focus an input programmatically. When you pass a ref to a `ref` attribute in JSX, like `
`, React will put the corresponding DOM element into `myRef.current`. You can read more about this in [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs)
+Вы можете использовать реф в качестве ссылки на любое значение. Однако, на практике рефы часто используются для доступа к DOM-элементам. Например, когда нужно программно сфокусироваться на элементе `input`. Когда вы устанавливаете `ref` через атрибут, `
`, React сохранит соответствующий DOM-элемент в качестве значения `myRef.current`. Вы можете больше прочитать об этом в [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs).
-- Refs are an escape hatch to hold onto values that aren't used for rendering. You won't need them often.
-- A ref is a plain JavaScript object with a single property called `current`, which you can read or set.
-- You can ask React to give you a ref by calling the `useRef` Hook.
-- Like state, refs let you retain information between re-renders of a component.
-- Unlike state, setting the ref's `current` value does not trigger a re-render.
-- Don't read or write `ref.current` during rendering. This makes your component hard to predict.
+- Рефф—это лазейка для хранения значений, которые не используются при рендере. Чаще всего вы можете обойтись без них.
+- Реф—это обычный JavaScript-объект с единственным свойством `curent`, которое доступно как для чтения, так и для записи.
+- Вы можете использовать реф, вызвав хук `useRef` из React.
+- Рефы позволяют вам сохранить данные между перерисовками компонента, как и в случае с состоянием.
+- В отличии от состояния, запись нового значения в `ref.current` не спровоцирует повторный рендер компонента.
+- Не читайте и не записывайте ничего в `ref.current` во время рендера. Это сделает поведение вашего компонента менее предсказуемым.
@@ -301,13 +301,13 @@ You can point a ref to any value. However, the most common use case for a ref is
-#### Fix a broken chat input {/*fix-a-broken-chat-input*/}
+#### Исправьте неработающий input в чате {/*fix-a-broken-chat-input*/}
-Type a message and click "Send". You will notice there is a three second delay before you see the "Sent!" alert. During this delay, you can see an "Undo" button. Click it. This "Undo" button is supposed to stop the "Sent!" message from appearing. It does this by calling [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) for the timeout ID saved during `handleSend`. However, even after "Undo" is clicked, the "Sent!" message still appears. Find why it doesn't work, and fix it.
+Введите сообщение и нажмите «Send». Можно заметить трёхсекундную задержку перед тем, как появится модальное окно с сообщением «Sent!». Во время этой задержки появляется кнопка «Undo». Кликните по ней. Предполагается, что кнопка «Undo» предотвратит появление сообщения «Sent!». Это происходит из-за вызова [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) для сохранения ID во время `handleSend`. Однако, даже после клика «Undo», сообщение все ещё появляется. Попробуйте разобраться, почему этот код не работает, и исправить его.
-Regular variables like `let timeoutID` don't "survive" between re-renders because every render runs your component (and initializes its variables) from scratch. Should you keep the timeout ID somewhere else?
+Обычные переменные, такие как `let timeoutID` не «выживают» между повторными рендерами, потому что каждый рендер запускает компонент (и инициализирует переменные) с нуля.
@@ -360,7 +360,7 @@ export default function Chat() {
-Whenever your component re-renders (such as when you set state), all local variables get initialized from scratch. This is why you can't save the timeout ID in a local variable like `timeoutID` and then expect another event handler to "see" it in the future. Instead, store it in a ref, which React will preserve between renders.
+Каждый раз когда компонент рендерится повторно (например, когда устанавливается новое состояние), все локальные переменные инициализируются с нуля. Поэтому вы не можете сохранить ID таймера в обычную переменную, как `timeoutID` и ожидать, что обработчик сможет «увидеть» её в будущем. Вместо этого сохраните её в реф, который React сохраняет между рендерами.
@@ -412,9 +412,9 @@ export default function Chat() {
-#### Fix a component failing to re-render {/*fix-a-component-failing-to-re-render*/}
+#### Исправьте ошибку при повторном рендере компонента {/*fix-a-component-failing-to-re-render*/}
-This button is supposed to toggle between showing "On" and "Off". However, it always shows "Off". What is wrong with this code? Fix it.
+Предполагается, что кнопка должна переключаться между отображением «On» и «Off». Но всегда отображается «Off». Что не так с эти кодом? Попробуйте исправить.
@@ -438,7 +438,7 @@ export default function Toggle() {
-In this example, the current value of a ref is used to calculate the rendering output: `{isOnRef.current ? 'On' : 'Off'}`. This is a sign that this information should not be in a ref, and should have instead been put in state. To fix it, remove the ref and use state instead:
+В этом примере текущее значение реф используется для вычисления того, что отобразится на странице: `{isOnRef.current ? 'On' : 'Off'}`. Это признак того, что эти данные не должны хранится в рефе, и вместо этого должны храниться в состоянии. Чтобы исправить, удалите реф и используйте состояние вместо него:
@@ -462,17 +462,17 @@ export default function Toggle() {
-#### Fix debouncing {/*fix-debouncing*/}
+#### Исправьте debouncing {/*fix-debouncing*/}
-In this example, all button click handlers are ["debounced".](https://redd.one/blog/debounce-vs-throttle) To see what this means, press one of the buttons. Notice how the message appears a second later. If you press the button while waiting for the message, the timer will reset. So if you keep clicking the same button fast many times, the message won't appear until a second *after* you stop clicking. Debouncing lets you delay some action until the user "stops doing things".
+В данном примере все обработчики событий для кнопок являются ["debounced".](https://redd.one/blog/debounce-vs-throttle) Чтобы понять, как это работает, кликните на одну из кнопок. Обратите внимание, что сообщение появляется через секунду. Если нажать на кнопку во время ожидания сообщения, таймер сбросится. Таким образом, если вы продолжите кликать одну и ту же кнопку много раз, сообщение не появится до тех пор, пока не пройдёт секунда _после_ последнего клика. Debouncing позволяет вам установить задержку до тех пор, пока пользователь «не прекратит делать что-то», прежде чем произойдёт какое-то действие.
-This example works, but not quite as intended. The buttons are not independent. To see the problem, click one of the buttons, and then immediately click another button. You'd expect that after a delay, you would see both button's messages. But only the last button's message shows up. The first button's message gets lost.
+Этот пример работает, но не совсем как было задумано. Кнопки не являются независимыми. Чтобы увидеть проблему, кликните на одну из кнопок и затем кликните на другую кнопку. Мы ожидаем увидеть два сообщения, которые привязаны к каждой кнопке. Но мы увидим только сообщение последней. Сообщение первой кнопки потерялось.
-Why are the buttons interfering with each other? Find and fix the issue.
+Почему кнопки конфликтуют между собой? Попробуйте найти и исправить проблему.
-The last timeout ID variable is shared between all `DebouncedButton` components. This is why clicking one button resets another button's timeout. Can you store a separate timeout ID for each button?
+Последний ID таймера используется во всех компонентах `DebouncedButton`. В этом причина того, что клик по одной кнопке сбрасывает таймер другой. Можно ли хранить ID таймера отдельно для каждой из кнопок?
@@ -525,7 +525,7 @@ button { display: block; margin: 10px; }
-A variable like `timeoutID` is shared between all components. This is why clicking on the second button resets the first button's pending timeout. To fix this, you can keep timeout in a ref. Each button will get its own ref, so they won't conflict with each other. Notice how clicking two buttons fast will show both messages.
+Переменная `timeoutID` была использована во всех компонентах. Поэтому клик по второй кнопке сбрасывал таймер ожидания первой. Чтобы это исправить, следует хранить таймер в рефе. Каждая кнопка получит свой реф, и вместе кнопки будут работать корректно. Обратите внимание, что быстрый клик по двум кнопкам покажет оба сообщения.
@@ -577,11 +577,11 @@ button { display: block; margin: 10px; }
-#### Read the latest state {/*read-the-latest-state*/}
+#### Прочитайте самое новое состояние {/*read-the-latest-state*/}
-In this example, after you press "Send", there is a small delay before the message is shown. Type "hello", press Send, and then quickly edit the input again. Despite your edits, the alert would still show "hello" (which was the value of state [at the time](/learn/state-as-a-snapshot#state-over-time) the button was clicked).
+В данном примере, после нажатия «Send» есть небольшая задержка прежде чем появится сообщение. Введите «hello», нажмите Send и потом снова отредактируйте поле ввода. Несмотря на редактирование, модальное окно все ещё показывает «hello» (эта строка была значением состояния [во время](/learn/state-as-a-snapshot#state-over-time), когда произошёл клик по кнопке).
-Usually, this behavior is what you want in an app. However, there may be occasional cases where you want some asynchronous code to read the *latest* version of some state. Can you think of a way to make the alert show the *current* input text rather than what it was at the time of the click?
+Как правило, именно такое поведение вам необходимо в вашем приложении. Тем не менее, могут возникнуть случаи, когда будет необходимость получить доступ к самой _последней_ версии состояния в каком-либо асинхронном коде. Можете ли вы найти решение, чтобы модальное окно показывало _текущий_ текст поля ввода вместо состояния, которое сохранилось во время клика?
@@ -616,7 +616,7 @@ export default function Chat() {
-State works [like a snapshot](/learn/state-as-a-snapshot), so you can't read the latest state from an asynchronous operation like a timeout. However, you can keep the latest input text in a ref. A ref is mutable, so you can read the `current` property at any time. Since the current text is also used for rendering, in this example, you will need *both* a state variable (for rendering), *and* a ref (to read it in the timeout). You will need to update the current ref value manually.
+Состояние работает как [снимок](/learn/state-as-a-snapshot), поэтому вы не сможете получить доступ к его последней версии из асинхронного кода, например внутри таймера. Однако, вы можете хранить последнее значение поля ввода в рефе. Реф является мутируемым, поэтому свойство `current` доступно для чтения в любое время. Поскольку, в этом примере, введённый текст также используется для рендера, вам необходимо использовать и *состояние* переменной (для рендера), и *реф* (для чтения внутри таймера). Обновляйте текущий реф вручную.
@@ -657,4 +657,4 @@ export default function Chat() {
-
+
\ No newline at end of file
diff --git a/src/content/learn/removing-effect-dependencies.md b/src/content/learn/removing-effect-dependencies.md
index dc34eedad..0a5151daa 100644
--- a/src/content/learn/removing-effect-dependencies.md
+++ b/src/content/learn/removing-effect-dependencies.md
@@ -882,7 +882,7 @@ const options2 = { serverUrl: 'https://localhost:1234', roomId: 'music' };
// These are two different objects!
console.log(Object.is(options1, options2)); // false
-````
+```
**Object and function dependencies can make your Effect re-synchronize more often than you need.**
@@ -968,7 +968,7 @@ const roomId2 = 'music';
// These two strings are the same!
console.log(Object.is(roomId1, roomId2)); // true
-````
+```
Thanks to this fix, the chat no longer re-connects if you edit the input:
diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md
index 84bf904cd..cb5ae5c75 100644
--- a/src/content/learn/render-and-commit.md
+++ b/src/content/learn/render-and-commit.md
@@ -1,27 +1,27 @@
---
-title: Render and Commit
+title: Рендер и фиксация
---
-Before your components are displayed on screen, they must be rendered by React. Understanding the steps in this process will help you think about how your code executes and explain its behavior.
+Прежде чем ваши компоненты появятся на экране, они должны быть отрисованы React. Понимая этапы этого процесса, вам будет проще судить о том, как исполняется ваш код, и объяснить его поведение
-* What rendering means in React
-* When and why React renders a component
-* The steps involved in displaying a component on screen
-* Why rendering does not always produce a DOM update
+* Что означает рендеринг в React.
+* Когда и почему React рендерит компонент.
+* Этапы отображения компонента на экране.
+* Почему рендеринг не всегда приводит к обновлению DOM.
-Imagine that your components are cooks in the kitchen, assembling tasty dishes from ingredients. In this scenario, React is the waiter who puts in requests from customers and brings them their orders. This process of requesting and serving UI has three steps:
+Представьте, что ваши компоненты — это повара на кухне, которые составляют вкусные блюда из ингредиентов. Тогда React — это официант, который передает запросы клиентов, а затем подает им их блюда. Этот процесс запроса и подачи пользовательского интерфейса состоит из трех этапов:
-1. **Triggering** a render (delivering the guest's order to the kitchen)
-2. **Rendering** the component (preparing the order in the kitchen)
-3. **Committing** to the DOM (placing the order on the table)
+1. **Триггер** рендеринга (передача заказа гостя на кухню)
+2. **Рендеринг** компонента (приготовление заказа на кухне)
+3. **Фиксация** в DOM (подача блюда на стол)
@@ -29,16 +29,16 @@ Imagine that your components are cooks in the kitchen, assembling tasty dishes f
-## Step 1: Trigger a render {/*step-1-trigger-a-render*/}
+## Часть 1: Триггер рендера {/*step-1-trigger-a-render*/}
-There are two reasons for a component to render:
+Рендер компонента происходит по двум причинам:
-1. It's the component's **initial render.**
-2. The component's (or one of its ancestors') **state has been updated.**
+1. Это его **начальный рендеринг.**
+2. Его **состояние** (или состояние его родителя) **был обновлён.**
-### Initial render {/*initial-render*/}
+### Начальный рендер {/*initial-render*/}
-When your app starts, you need to trigger the initial render. Frameworks and sandboxes sometimes hide this code, but it's done by calling [`createRoot`](/reference/react-dom/client/createRoot) with the target DOM node, and then calling its `render` method with your component:
+Когда ваше приложение запускается, вам необходимо запустить начальный рендеринг. Фреймворки и песочницы иногда скрывают этот код, но это делается вызовом функции [`createRoot`](/reference/react-dom/client/createRoot) с целевым DOM-узлом, а затем вызовом его метода `render` c вашим компонентом:
@@ -63,11 +63,11 @@ export default function Image() {
-Try commenting out the `root.render()` call and see the component disappear!
+Попробуйте закомментировать вызов `root.render()` и увидите, как компонент исчезнет!
-### Re-renders when state updates {/*re-renders-when-state-updates*/}
+### Ре-рендер, когда состояние обновляется {/*re-renders-when-state-updates*/}
-Once the component has been initially rendered, you can trigger further renders by updating its state with the [`set` function.](/reference/react/useState#setstate) Updating your component's state automatically queues a render. (You can imagine these as a restaurant guest ordering tea, dessert, and all sorts of things after putting in their first order, depending on the state of their thirst or hunger.)
+После того как компонент был первоначально отрендерен, вы можете инициировать последующие рендеры, обновляя его состояние с помощью функции [`set`](/reference/react/useState#setstate) Обновление состояние компонента автоматически ставит его в очередь на рендер. (Вы можете представить это как посетитель ресторана, который после первого заказа заказывает чай, десерт и всевозможные вещи, в зависимости от состояния жажды или голода).
@@ -75,16 +75,16 @@ Once the component has been initially rendered, you can trigger further renders
-## Step 2: React renders your components {/*step-2-react-renders-your-components*/}
+## Часть 2: React рендерит ваш компонент {/*step-2-react-renders-your-components*/}
-After you trigger a render, React calls your components to figure out what to display on screen. **"Rendering" is React calling your components.**
+После запуска рендера React вызывает ваши компоненты, чтобы определить, что отобразить на экране. **«Рендеринг» — это обращение React к вашим компонентам*.
-* **On initial render,** React will call the root component.
-* **For subsequent renders,** React will call the function component whose state update triggered the render.
+* **На начальном рендере,** React вызовет корневой компонент.
+* **Для последующих ре-рендеров** React вызовет функцию компонента, где обновился стейт и выполнит его ре-рендер.
-This process is recursive: if the updated component returns some other component, React will render _that_ component next, and if that component also returns something, it will render _that_ component next, and so on. The process will continue until there are no more nested components and React knows exactly what should be displayed on screen.
+Этот процесс рекурсивен: если обновленный компонент возвращает какой-то другой компонент, React будет рендерить _этот_ компонент следующим, и если этот компонент тоже что-то возвращает, он будет рендерить _этот_ компонент следующим, и так далее. Этот процесс будет продолжаться до тех пор, пока не останется вложенных компонентов и React не будет точно знать, что должно быть отображено на экране.
-In the following example, React will call `Gallery()` and `Image()` several times:
+В следующем примере React вызовет `Gallery()` и `Image()` несколько раз:
@@ -124,36 +124,36 @@ img { margin: 0 10px 10px 0; }
-* **During the initial render,** React will [create the DOM nodes](https://developer.mozilla.org/docs/Web/API/Document/createElement) for ``, `
`, and three `` tags.
-* **During a re-render,** React will calculate which of their properties, if any, have changed since the previous render. It won't do anything with that information until the next step, the commit phase.
+* **На начальном рендере,** React [создаст DOM ноды](https://developer.mozilla.org/docs/Web/API/Document/createElement) для ``, `
`, и трёзх `` тегов.
+* **Во время повторного ре-рендеринга,** React вычислит, какие из их свойств, если таковые имеются, изменились с момента предыдущего рендеринга. Он ничего не будет делать с этой информацией до следующего шага, фазы фиксации.
-Rendering must always be a [pure calculation](/learn/keeping-components-pure):
+Рендеринг всегда должен быть [чистым вычислением.](/learn/keeping-components-pure):
-* **Same inputs, same output.** Given the same inputs, a component should always return the same JSX. (When someone orders a salad with tomatoes, they should not receive a salad with onions!)
-* **It minds its own business.** It should not change any objects or variables that existed before rendering. (One order should not change anyone else's order.)
+* **Одни и те же входные данные, один и тот же результат.** При одинаковых входящих данных компонент всегда должен возвращать один и тот же JSX. (Когда кто-то заказывает салат с помидорами, то он не должен получить салат с луком!)
+* **Занимается только своей задачей.** Не изменять объекты или переменные, существовавшие до рендеринга. (Один заказ не должен влиять на другой заказ).
-Otherwise, you can encounter confusing bugs and unpredictable behavior as your codebase grows in complexity. When developing in "Strict Mode", React calls each component's function twice, which can help surface mistakes caused by impure functions.
+В противном случае вы можете столкнуться с непонятными ошибками и непредсказуемым поведением по мере роста сложности вашей кодовой базы. При разработке в "строгом режиме" React вызывает функцию каждого компонента дважды, что может помочь выявить ошибки, вызванные нечистыми функциями.
-#### Optimizing performance {/*optimizing-performance*/}
+#### Оптимизируем производительность {/*optimizing-performance*/}
-The default behavior of rendering all components nested within the updated component is not optimal for performance if the updated component is very high in the tree. If you run into a performance issue, there are several opt-in ways to solve it described in the [Performance](https://reactjs.org/docs/optimizing-performance.html) section. **Don't optimize prematurely!**
+Поведение по умолчанию — рендеринг всех компонентов, вложенных в обновленный компонент, — не является оптимальным с точки зрения производительности, если обновляемый компонент находится очень высоко в дереве. Если вы столкнулись с проблемой производительности, есть несколько способов ее решения, описанных в разделе [Производительность](https://reactjs.org/docs/optimizing-performance.html). **Не оптимизируйте преждевременно!**
-## Step 3: React commits changes to the DOM {/*step-3-react-commits-changes-to-the-dom*/}
+## Часть 3: React фиксирует изменения в DOM {/*step-3-react-commits-changes-to-the-dom*/}
-After rendering (calling) your components, React will modify the DOM.
+После рендеринга (вызова) ваших компонентов React модифицирует 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.
+* **На начальном рендере,** React использует [`appendChild()`](https://developer.mozilla.org/ru/docs/Web/API/Node/appendChild) DOM API, чтобы вставить все DOM ноды, которые он создал на экране.
+* **Для ре-рендеров,** React будет применять минимально необходимые операции (вычисляемые во время рендеринга!), чтобы DOM соответствовал последнему выводу рендеринга.
-**React only changes the DOM nodes if there's a difference between renders.** For example, here is a component that re-renders with different props passed from its parent every second. Notice how you can add some text into the ``, updating its `value`, but the text doesn't disappear when the component re-renders:
+**React изменяет узлы DOM только если есть разница между рендерами.** Например, вот компонент, который рендерится с разными пропсами, передаваемыми от родителя каждую секунду. Обратите внимание, как вы можете добавить некоторый текст в ``, обновляя его `значение`, но текст не исчезает при повторном рендеринге компонента:
@@ -193,21 +193,21 @@ export default function App() {
-This works because during this last step, React only updates the content of `
` with the new `time`. It sees that the `` appears in the JSX in the same place as last time, so React doesn't touch the ``—or its `value`!
-## Epilogue: Browser paint {/*epilogue-browser-paint*/}
+Это работает, потому что в предыдущий раз React обновил значение `
` с новым `time`. Он видит, что `` появляется в том же месте JSX, поэтому React не трогает ``— или его `value`!
+## Заключительная часть: Браузерная отрисовка {/*epilogue-browser-paint*/}
-After rendering is done and React updated the DOM, the browser will repaint the screen. Although this process is known as "browser rendering", we'll refer to it as "painting" to avoid confusion throughout the docs.
+После того как рендеринг завершен и React обновил DOM, браузер перерисовывает экран. Хотя этот процесс известен как «браузерный рендеринг», мы будем называть его «рисованием», чтобы избежать путаницы в документации.
-* Any screen update in a React app happens in three steps:
- 1. Trigger
- 2. Render
- 3. Commit
-* You can use Strict Mode to find mistakes in your components
-* React does not touch the DOM if the rendering result is the same as last time
+* Любое обновление экрана в приложении React происходит в три этапа:
+ 1. Триггер
+ 2. Рендеринг
+ 3. Фиксация
+* Вы можете использовать строгий режим для поиска ошибок в ваших компонентах.
+* React не трогает DOM, если результат рендеринга такой же, как и в прошлый раз.
diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md
index 45b60240b..99e09d624 100644
--- a/src/content/learn/rendering-lists.md
+++ b/src/content/learn/rendering-lists.md
@@ -1,74 +1,74 @@
---
-title: Rendering Lists
+title: Рендер списков
---
-You will often want to display multiple similar components from a collection of data. You can use the [JavaScript array methods](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array#) to manipulate an array of data. On this page, you'll use [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) and [`map()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map) with React to filter and transform your array of data into an array of components.
+Часто возникает необходимость отображения ряда схожих компонентов на основе набора данных. Для этого можно воспользоваться [методами массивов JavaScript](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array) для манипулирования массивом данных. На этой странице вы будете использовать [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) и [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) с React для фильтрации и преобразования массива данных в массив компонентов.
-* How to render components from an array using JavaScript's `map()`
-* How to render only specific components using JavaScript's `filter()`
-* When and why to use React keys
+* Как рендерить компоненты из массива, используя `map()`
+* Как рендерить только определенные компоненты, используя `filter()`
+* Когда и зачем использовать React-ключи
-## Rendering data from arrays {/*rendering-data-from-arrays*/}
+## Рендер данных из массивов {/*rendering-data-from-arrays*/}
-Say that you have a list of content.
+Предположим, у вас есть список контента.
```js
```
-The only difference among those list items is their contents, their data. You will often need to show several instances of the same component using different data when building interfaces: from lists of comments to galleries of profile images. In these situations, you can store that data in JavaScript objects and arrays and use methods like [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) to render lists of components from them.
+Единственная разница между этими элементами списка - их содержимое, их данные. При построении интерфейсов часто нужно показывать несколько экземпляров одного и того же компонента, используя различные данные: от списков комментариев до галерей профилей. В таких ситуациях вы можете хранить эти данные в объектах и массивах JavaScript и использовать методы, такие как [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) и [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), чтобы рендерить списки компонентов с данными из них.
-Here’s a short example of how to generate a list of items from an array:
+Вот короткий пример того, как сгенерировать список элементов из массива:
-1. **Move** the data into an array:
+1. **Переместите** данные в массив:
```js
const people = [
- 'Creola Katherine Johnson: mathematician',
- 'Mario José Molina-Pasquel Henríquez: chemist',
- 'Mohammad Abdus Salam: physicist',
- 'Percy Lavon Julian: chemist',
- 'Subrahmanyan Chandrasekhar: astrophysicist'
+ 'Креола Кэтрин Джонсон (Creola Katherine Johnson): математик',
+ 'Марио Молина (Mario José Molina-Pasquel Henríquez): химик',
+ 'Мухаммад Абдус Салам (Mohammad Abdus Salam): физик',
+ 'Перси Джулиан (Percy Lavon Julian): химик',
+ 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar): астрофизик'
];
```
-2. **Map** the `people` members into a new array of JSX nodes, `listItems`:
+2. **Преобразуйте** элементы массива `people` в новый массив JSX-узлов, `listItems`, используя метод `map()`:
```js
const listItems = people.map(person =>
{person}
);
```
-3. **Return** `listItems` from your component wrapped in a `
`:
+3. **Верните** `listItems` из вашего компонента, обернув их в тег `
`:
```js
return
{listItems}
;
```
-Here is the result:
+Вот что должно получиться в итоге:
```js
const people = [
- 'Creola Katherine Johnson: mathematician',
- 'Mario José Molina-Pasquel Henríquez: chemist',
- 'Mohammad Abdus Salam: physicist',
- 'Percy Lavon Julian: chemist',
- 'Subrahmanyan Chandrasekhar: astrophysicist'
+ 'Креола Кэтрин Джонсон (Creola Katherine Johnson): математик',
+ 'Марио Молина (Mario José Molina-Pasquel Henríquez): химик',
+ 'Мухаммад Абдус Салам (Mohammad Abdus Salam): физик',
+ 'Перси Джулиан (Percy Lavon Julian): химик',
+ 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar): астрофизик'
];
export default function List() {
@@ -85,7 +85,7 @@ li { margin-bottom: 10px; }
-Notice the sandbox above displays a console error:
+Обратите внимание, что в консоли песочницы отображается ошибка:
@@ -93,47 +93,47 @@ Warning: Each child in a list should have a unique "key" prop.
-You'll learn how to fix this error later on this page. Before we get to that, let's add some structure to your data.
+Вы узнаете о том, как исправить эту ошибку позже на этой странице. Прежде чем перейти к этому, давайте добавим некоторую структуру к данным.
-## Filtering arrays of items {/*filtering-arrays-of-items*/}
+## Фильтрация массивов элементов {/*filtering-arrays-of-items*/}
-This data can be structured even more.
+Структуру этих данных можно улучшить.
```js
const people = [{
id: 0,
- name: 'Creola Katherine Johnson',
- profession: 'mathematician',
+ name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)',
+ profession: 'математик',
}, {
id: 1,
- name: 'Mario José Molina-Pasquel Henríquez',
- profession: 'chemist',
+ name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)',
+ profession: 'химик',
}, {
id: 2,
- name: 'Mohammad Abdus Salam',
- profession: 'physicist',
+ name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)',
+ profession: 'физик',
}, {
- name: 'Percy Lavon Julian',
- profession: 'chemist',
+ name: 'Перси Джулиан (Percy Lavon Julian)',
+ profession: 'химик',
}, {
- name: 'Subrahmanyan Chandrasekhar',
- profession: 'astrophysicist',
+ name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)',
+ profession: 'астрофизик',
}];
```
-Let's say you want a way to only show people whose profession is `'chemist'`. You can use JavaScript's `filter()` method to return just those people. This method takes an array of items, passes them through a “test” (a function that returns `true` or `false`), and returns a new array of only those items that passed the test (returned `true`).
+Допустим, вам нужен способ отображать только людей, чья профессия `'химик'`. Вы можете использовать метод JavaScript `filter()` чтобы вернуть только этих людей. Этот метод принимает массив элементов, пропускает их через «тест» (функция, которая возвращает `true` или `false`) и возвращает новый массив только из тех элементов, которые прошли тест (вернули `true`).
-You only want the items where `profession` is `'chemist'`. The "test" function for this looks like `(person) => person.profession === 'chemist'`. Here's how to put it together:
+В нашем случае мы хотим отобразить только те элементы, где `profession` является `'химик'`. «Тест» для этого выглядит так: `(person) => person.profession === 'химик'`. Вот как собрать все воедино:
-1. **Create** a new array of just “chemist” people, `chemists`, by calling `filter()` on the `people` filtering by `person.profession === 'chemist'`:
+1. **Создайте** новый массив только из людей с профессией `'chemist'`, вызвав `filter()` на `people` для фильтрации по `person.profession === 'химик'`:
```js
const chemists = people.filter(person =>
- person.profession === 'chemist'
+ person.profession === 'химик'
);
```
-2. Now **map** over `chemists`:
+2. Теперь **преобразуйте** элементы массива `chemists`:
```js {1,13}
const listItems = chemists.map(person =>
@@ -144,14 +144,14 @@ const listItems = chemists.map(person =>
/>
);
@@ -187,33 +187,33 @@ export default function List() {
```js data.js
export const people = [{
id: 0,
- name: 'Creola Katherine Johnson',
- profession: 'mathematician',
- accomplishment: 'spaceflight calculations',
+ name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)',
+ profession: 'математик',
+ accomplishment: 'расчёты для космических полетов',
imageId: 'MK3eW3A'
}, {
id: 1,
- name: 'Mario José Molina-Pasquel Henríquez',
- profession: 'chemist',
- accomplishment: 'discovery of Arctic ozone hole',
+ name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)',
+ profession: 'химик',
+ accomplishment: 'обнаружение дыр в озоновом слое',
imageId: 'mynHUSa'
}, {
id: 2,
- name: 'Mohammad Abdus Salam',
- profession: 'physicist',
- accomplishment: 'electromagnetism theory',
+ name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)',
+ profession: 'физик',
+ accomplishment: 'открытие теории электромагнетизма',
imageId: 'bE7W1ji'
}, {
id: 3,
- name: 'Percy Lavon Julian',
- profession: 'chemist',
- accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
+ name: 'Перси Джулиан (Percy Lavon Julian)',
+ profession: 'химик',
+ accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток',
imageId: 'IOjWm71'
}, {
id: 4,
- name: 'Subrahmanyan Chandrasekhar',
- profession: 'astrophysicist',
- accomplishment: 'white dwarf star mass calculations',
+ name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)',
+ profession: 'астрофизик',
+ accomplishment: 'расчёт массы белого карлика',
imageId: 'lrWQx8l'
}];
```
@@ -244,29 +244,30 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-Arrow functions implicitly return the expression right after `=>`, so you didn't need a `return` statement:
+Стрелочные функции неявно возвращают результат выражения сразу после `=>`, поэтому использовать ключевое слово `return` не нужно:
```js
const listItems = chemists.map(person =>
-
...
// Implicit return!
+
...
// Неявный возврат!
);
```
-However, **you must write `return` explicitly if your `=>` is followed by a `{` curly brace!**
+Однако, **вы должны явно вызвать `return`, если после `=>` следует фигурная скобка!**
+
```js
-const listItems = chemists.map(person => { // Curly brace
+const listItems = chemists.map(person => { // Фигурная скобка
return
...
;
});
```
-Arrow functions containing `=> {` are said to have a ["block body".](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#function_body) They let you write more than a single line of code, but you *have to* write a `return` statement yourself. If you forget it, nothing gets returned!
+Стрелочные функции, содержащие `=> {` считаются функциями с ["блочной формой".](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions#%D1%82%D0%B5%D0%BB%D0%BE_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8) Они позволяют писать более одной строки кода, но при этом *необходимо* явно вызвать `return`. Если вы забудете это сделать, функция ничего не вернет!
-## Keeping list items in order with `key` {/*keeping-list-items-in-order-with-key*/}
+## Сохранение порядка элементов списка с помощью `key` {/*keeping-list-items-in-order-with-key*/}
-Notice that all the sandboxes above show an error in the console:
+Заметьте, что все песочницы выше показывают ошибку в консоли:
@@ -274,7 +275,7 @@ Warning: Each child in a list should have a unique "key" prop.
-You need to give each array item a `key` -- a string or a number that uniquely identifies it among other items in that array:
+Чтобы решить эту ошибку необходимо присвоить каждому элементу массива ключ (`key`) -- строку или число, которое уникально отличает данный элемент среди других элементов этого массива:
```js
...
@@ -282,13 +283,13 @@ You need to give each array item a `key` -- a string or a number that uniquely i
-JSX elements directly inside a `map()` call always need keys!
+JSX-элементы, созданные внутри `map()` всегда должны иметь ключи!
-Keys tell React which array item each component corresponds to, so that it can match them up later. This becomes important if your array items can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen `key` helps React infer what exactly has happened, and make the correct updates to the DOM tree.
+Ключи позволяют React узнать к какому элементу массива соответствует каждый компонент, чтобы позже сопоставить их. Это важно, если элементы массива могут перемещаться (например, из-за сортировки), добавляться или удаляться. Хорошо выбранный ключ помогает React понять, какое именно изменение произошло, и правильно обновить DOM дерево.
-Rather than generating keys on the fly, you should include them in your data:
+Вместо генерации ключей на лету, вы должны включать их в свои данные:
@@ -305,8 +306,8 @@ export default function List() {
/>
);
@@ -316,34 +317,34 @@ export default function List() {
```js data.js active
export const people = [{
- id: 0, // Used in JSX as a key
- name: 'Creola Katherine Johnson',
- profession: 'mathematician',
- accomplishment: 'spaceflight calculations',
+ id: 0, // Используется в JSX в качестве ключа
+ name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)',
+ profession: 'математик',
+ accomplishment: 'расчёты для космических полетов',
imageId: 'MK3eW3A'
}, {
- id: 1, // Used in JSX as a key
- name: 'Mario José Molina-Pasquel Henríquez',
- profession: 'chemist',
- accomplishment: 'discovery of Arctic ozone hole',
+ id: 1, // Используется в JSX в качестве ключа
+ name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)',
+ profession: 'химик',
+ accomplishment: 'обнаружение дыр в озоновом слое',
imageId: 'mynHUSa'
}, {
- id: 2, // Used in JSX as a key
- name: 'Mohammad Abdus Salam',
- profession: 'physicist',
- accomplishment: 'electromagnetism theory',
+ id: 2, // Используется в JSX в качестве ключа
+ name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)',
+ profession: 'физик',
+ accomplishment: 'открытие теории электромагнетизма',
imageId: 'bE7W1ji'
}, {
- id: 3, // Used in JSX as a key
- name: 'Percy Lavon Julian',
- profession: 'chemist',
- accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
+ id: 3, // Используется в JSX в качестве ключа
+ name: 'Перси Джулиан (Percy Lavon Julian)',
+ profession: 'химик',
+ accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток',
imageId: 'IOjWm71'
}, {
- id: 4, // Used in JSX as a key
- name: 'Subrahmanyan Chandrasekhar',
- profession: 'astrophysicist',
- accomplishment: 'white dwarf star mass calculations',
+ id: 4, // Используется в JSX в качестве ключа
+ name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)',
+ profession: 'астрофизик',
+ accomplishment: 'расчёт массы белого карлика',
imageId: 'lrWQx8l'
}];
```
@@ -374,11 +375,11 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-#### Displaying several DOM nodes for each list item {/*displaying-several-dom-nodes-for-each-list-item*/}
+#### Отображение нескольких DOM-узлов для каждого элемента списка {/*displaying-several-dom-nodes-for-each-list-item*/}
-What do you do when each item needs to render not one, but several DOM nodes?
+Как поступить, если каждый элемент должен отображать не один, а несколько DOM-узлов?
-The short [`<>...>` Fragment](/reference/react/Fragment) syntax won't let you pass a key, so you need to either group them into a single `
`, or use the slightly longer and [more explicit `` syntax:](/reference/react/Fragment#rendering-a-list-of-fragments)
+Краткий синтаксис [`<>...>` фрагмента](/reference/react/Fragment) не позволяет передавать ключ, поэтому нужно либо объединить их в один `
`, либо использовать чуть более длинный и [более явный ``:](/reference/react/Fragment#rendering-a-list-of-fragments)
```js
import { Fragment } from 'react';
@@ -393,46 +394,47 @@ const listItems = people.map(person =>
);
```
-Fragments disappear from the DOM, so this will produce a flat list of `
`, `
`, `
`, `
`, and so on.
+Фрагменты исчезают из DOM, поэтому это приведет к плоскому списку элементов `
`, `
`, `
`, `
`, и т.д.
-### Where to get your `key` {/*where-to-get-your-key*/}
+### Откуда взять ключ {/*where-to-get-your-key*/}
+
+Разные источники данных предоставляют разные источники для ключей:
-Different sources of data provide different sources of keys:
+* **Данные из базы данных:** Если ваши данные приходят с базы данных, то вы можете использовать ключи/ID с базы данных, которые по своей природе уникальны.
-* **Data from a database:** If your data is coming from a database, you can use the database keys/IDs, which are unique by nature.
-* **Locally generated data:** If your data is generated and persisted locally (e.g. notes in a note-taking app), use an incrementing counter, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) or a package like [`uuid`](https://www.npmjs.com/package/uuid) when creating items.
+* **Локальные данные:** Если ваши данные генерируются и хранятся локально (к примеру, заметки в приложении для ведений заметок), используйте инкрементный счетчик, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) или пакет [`uuid`](https://www.npmjs.com/package/uuid) при создании элементов.
-### Rules of keys {/*rules-of-keys*/}
+### Правила ключей {/*rules-of-keys*/}
-* **Keys must be unique among siblings.** However, it’s okay to use the same keys for JSX nodes in _different_ arrays.
-* **Keys must not change** or that defeats their purpose! Don't generate them while rendering.
+* **Ключи должны быть уникальны среди своих соседних элементов.** Однако, можно использовать одинаковые ключи для JSX-узлов в _разных_ массивах.
+* **Ключи не должны меняться**, так как это лишает их смысла! Не генерируйте их во время рендеринга.
-### Why does React need keys? {/*why-does-react-need-keys*/}
+### Почему React нужны ключи? {/*why-does-react-need-keys*/}
-Imagine that files on your desktop didn't have names. Instead, you'd refer to them by their order -- the first file, the second file, and so on. You could get used to it, but once you delete a file, it would get confusing. The second file would become the first file, the third file would be the second file, and so on.
+Представьте что у файлов на вашем рабочем столе не было бы имен. Взамен, вы бы ссылались на них по их порядку -- первый файл, второй файл, и т.д. Возможно к этому и можно привыкнуть, но когда вы удалите какой-либо файл, порядок изменится и все станет запутанным. Второй файл станет первым, третий файл станет вторым, и т. д.
-File names in a folder and JSX keys in an array serve a similar purpose. They let us uniquely identify an item between its siblings. A well-chosen key provides more information than the position within the array. Even if the _position_ changes due to reordering, the `key` lets React identify the item throughout its lifetime.
+Названия файлов в папке и JSX ключи в массиве имеют схожую цель. Они позволяют нам отличать элементы от их других элементов в массиве. А хорошо выбранный ключ предоставляет больше информации, чем позиция в массиве. Даже если _позиция_ изменится из-за смены порядка, `key` позволит React идентифицировать элемент на протяжении всего существования элемента.
-You might be tempted to use an item's index in the array as its key. In fact, that's what React will use if you don't specify a `key` at all. But the order in which you render items will change over time if an item is inserted, deleted, or if the array gets reordered. Index as a key often leads to subtle and confusing bugs.
+Возможно вам захочется использовать индекс элемента в массиве в качестве ключа. В действительности, это то, что React будет использовать, если вы не укажете `key`. Но порядок, в котором вы рендерите элементы, может поменяться со временем, если какой-либо элемент будет вставлен, удален или если массив будет переупорядочен. Индекс в качестве ключа часто приводит к коварным и сбивающим с толку ошибкам.
-Similarly, do not generate keys on the fly, e.g. with `key={Math.random()}`. This will cause keys to never match up between renders, leading to all your components and DOM being recreated every time. Not only is this slow, but it will also lose any user input inside the list items. Instead, use a stable ID based on the data.
+Аналогично, не генерируйте ключи на лету, например, с помощью `key={Math.random()}`. Это приведет к тому, что ключи никогда не будут совпадать между рендерами, что приведет к пересозданию всех ваших компонентов и DOM при каждом рендере. Это не только медленно, но также приведет к потере любых данных введённых пользователем внутри элементов списка. Вместо этого используйте стабильный ID, основанный на данных.
-Note that your components won't receive `key` as a prop. It's only used as a hint by React itself. If your component needs an ID, you have to pass it as a separate prop: ``.
+Заметьте, что ваши компоненты не получат `key` в качестве пропа. Он используется только как подсказка для React. Если ваш компонент нуждается в ID, вы должны передать его как отдельный проп: ``..
-On this page you learned:
+На этой странице вы узнали:
-* How to move data out of components and into data structures like arrays and objects.
-* How to generate sets of similar components with JavaScript's `map()`.
-* How to create arrays of filtered items with JavaScript's `filter()`.
-* Why and how to set `key` on each component in a collection so React can keep track of each of them even if their position or data changes.
+* Как перенести данные из компонентов в структуры данных, такие как массивы и объекты.
+* Как создавать коллекции схожих компонентов с помощью JavaScript `map()`.
+* Как создавать массивы отфильтрованных элементов с помощью JavaScript `filter()`.
+* Зачем и как присваивать ключ каждому компоненту в коллекции, чтобы React мог отслеживать изменения каждого из них.
@@ -440,11 +442,11 @@ On this page you learned:
-#### Splitting a list in two {/*splitting-a-list-in-two*/}
+#### Разделение списка на два {/*splitting-a-list-in-two*/}
-This example shows a list of all people.
+Этот пример показывает список всех людей в `people`.
-Change it to show two separate lists one after another: **Chemists** and **Everyone Else.** Like previously, you can determine whether a person is a chemist by checking if `person.profession === 'chemist'`.
+Поменяйте код так, чтобы он показывал два списка один за другим: **Химики** и **Все остальные**. Как и раньше, вы можете определить, является ли человек химиком, проверив `person.profession === 'химик'`.
@@ -461,14 +463,14 @@ export default function List() {
/>
-In this solution, the `map` calls are placed directly inline into the parent `
` elements, but you could introduce variables for them if you find that more readable.
+В данном решении, вызовы `map` помещены непосредственно в родительские элементы `
`, но вы можете вынести их в отдельные переменные, если cчитаете это более читабельным.
-There is still a bit duplication between the rendered lists. You can go further and extract the repetitive parts into a `` component:
+Между отображаемыми списками все еще существует небольшое дублирование. Вы можете пойти дальше и извлечь повторяющиеся части в компонент ``:
@@ -671,8 +673,8 @@ function ListSection({ title, people }) {
/>
@@ -707,33 +709,33 @@ export default function List() {
```js data.js
export const people = [{
id: 0,
- name: 'Creola Katherine Johnson',
- profession: 'mathematician',
- accomplishment: 'spaceflight calculations',
+ name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)',
+ profession: 'математик',
+ accomplishment: 'расчёты для космических полетов',
imageId: 'MK3eW3A'
}, {
id: 1,
- name: 'Mario José Molina-Pasquel Henríquez',
- profession: 'chemist',
- accomplishment: 'discovery of Arctic ozone hole',
+ name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)',
+ profession: 'химик',
+ accomplishment: 'обнаружение дыр в озоновом слое',
imageId: 'mynHUSa'
}, {
id: 2,
- name: 'Mohammad Abdus Salam',
- profession: 'physicist',
- accomplishment: 'electromagnetism theory',
+ name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)',
+ profession: 'физик',
+ accomplishment: 'открытие теории электромагнетизма',
imageId: 'bE7W1ji'
}, {
id: 3,
- name: 'Percy Lavon Julian',
- profession: 'chemist',
- accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
+ name: 'Перси Джулиан (Percy Lavon Julian)',
+ profession: 'химик',
+ accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток',
imageId: 'IOjWm71'
}, {
id: 4,
- name: 'Subrahmanyan Chandrasekhar',
- profession: 'astrophysicist',
- accomplishment: 'white dwarf star mass calculations',
+ name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)',
+ profession: 'астрофизик',
+ accomplishment: 'расчёт массы белого карлика',
imageId: 'lrWQx8l'
}];
```
@@ -762,9 +764,9 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-A very attentive reader might notice that with two `filter` calls, we check each person's profession twice. Checking a property is very fast, so in this example it's fine. If your logic was more expensive than that, you could replace the `filter` calls with a loop that manually constructs the arrays and checks each person once.
+Очень внимательный читатель мог бы заметить, что при двух вызовах `filter` мы дважды проверяем профессию каждого человека. Проверка свойства происходит очень быстро, поэтому в данном примере это нормально. Если бы ваша логика была более затратна, вы могли бы заменить вызовы `filter` на цикл, который вручную создает массивы и проверяет каждого человека один раз.
-In fact, if `people` never change, you could move this code out of your component. From React's perspective, all that matters is that you give it an array of JSX nodes in the end. It doesn't care how you produce that array:
+К тому же, если `people` никогда не меняется, вы можете вынести этот код из вашего компонента. С точки зрения React, единственное что имеет значение, это то, что вы предоставляете массив JSX-узлов в конце. React не важно, как вы создаете этот массив:
@@ -775,7 +777,7 @@ import { getImageUrl } from './utils.js';
let chemists = [];
let everyoneElse = [];
people.forEach(person => {
- if (person.profession === 'chemist') {
+ if (person.profession === 'химик') {
chemists.push(person);
} else {
everyoneElse.push(person);
@@ -795,8 +797,8 @@ function ListSection({ title, people }) {
/>
-#### Nested lists in one component {/*nested-lists-in-one-component*/}
+#### Вложенные списки в одном компоненте {/*nested-lists-in-one-component*/}
-Make a list of recipes from this array! For each recipe in the array, display its name as an `
` and list its ingredients in a `
`.
+Создайте список рецептов из данного массива! Для каждого рецепта в массиве отобразите название внутри `
` и перечислите ингредиенты в `
`.
-This will require nesting two different `map` calls.
+Для этого потребуется вложение двух разных вызовов `map`.
@@ -900,7 +902,7 @@ import { recipes } from './data.js';
export default function RecipeList() {
return (
-
Recipes
+
Рецепты
);
}
@@ -909,16 +911,16 @@ export default function RecipeList() {
```js data.js
export const recipes = [{
id: 'greek-salad',
- name: 'Greek Salad',
- ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta']
+ name: 'Греческий салат',
+ ingredients: ['помидоры', 'огурец', 'лук', 'оливки', 'сыр фета']
}, {
id: 'hawaiian-pizza',
- name: 'Hawaiian Pizza',
- ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple']
+ name: 'Гавайская пицца',
+ ingredients: ['тесто для пиццы', 'соус для пиццы', 'моцарелла', 'ветчина', 'ананас']
}, {
id: 'hummus',
- name: 'Hummus',
- ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini']
+ name: 'Хумус',
+ ingredients: ['нут', 'оливковое масло', 'зубчики чеснока', 'лимон', 'тахини']
}];
```
@@ -926,7 +928,7 @@ export const recipes = [{
-Here is one way you could go about it:
+Вот один из способов, как вы можете это сделать:
@@ -936,7 +938,7 @@ import { recipes } from './data.js';
export default function RecipeList() {
return (
-
Recipes
+
Рецепты
{recipes.map(recipe =>
{recipe.name}
@@ -957,28 +959,28 @@ export default function RecipeList() {
```js data.js
export const recipes = [{
id: 'greek-salad',
- name: 'Greek Salad',
- ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta']
+ name: 'Греческий салат',
+ ingredients: ['помидоры', 'огурец', 'лук', 'оливки', 'сыр фета']
}, {
id: 'hawaiian-pizza',
- name: 'Hawaiian Pizza',
- ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple']
+ name: 'Гавайская пицца',
+ ingredients: ['тесто для пиццы', 'соус для пиццы', 'моцарелла', 'ветчина', 'ананас']
}, {
id: 'hummus',
- name: 'Hummus',
- ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini']
+ name: 'Хумус',
+ ingredients: ['нут', 'оливковое масло', 'зубчики чеснока', 'лимон', 'тахини']
}];
```
-Each of the `recipes` already includes an `id` field, so that's what the outer loop uses for its `key`. There is no ID you could use to loop over ingredients. However, it's reasonable to assume that the same ingredient won't be listed twice within the same recipe, so its name can serve as a `key`. Alternatively, you could change the data structure to add IDs, or use index as a `key` (with the caveat that you can't safely reorder ingredients).
+Каждый из рецептов уже содержит поле `id`, поэтому это и используется внешним циклом в качестве ключа. Нет ID, который можно было бы использовать для перебора ингредиентов. Однако разумно предположить, что один и тот же ингредиент не будет перечислен дважды в одном рецепте, поэтому его имя может служить в качестве ключа. Как вариант, вы можете изменить структуру данных, чтобы добавить ID, или же использовать индекс в качестве ключа (с оговоркой, что вы не можете безопасно изменять порядок ингредиентов).
-#### Extracting a list item component {/*extracting-a-list-item-component*/}
+#### Извлечение компонента элемента списка {/*extracting-a-list-item-component*/}
-This `RecipeList` component contains two nested `map` calls. To simplify it, extract a `Recipe` component from it which will accept `id`, `name`, and `ingredients` props. Where do you place the outer `key` and why?
+Компонент `RecipeList` содержит два вложенных вызова `map`. Чтобы упростить его, извлеките компонент `Recipe`, который будет принимать пропсы `id`, `name` и `ingredients`. Где вы разместите внешний `key` и почему?
@@ -988,7 +990,7 @@ import { recipes } from './data.js';
export default function RecipeList() {
return (
-
Recipes
+
Рецепты
{recipes.map(recipe =>
{recipe.name}
@@ -1009,16 +1011,16 @@ export default function RecipeList() {
```js data.js
export const recipes = [{
id: 'greek-salad',
- name: 'Greek Salad',
- ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta']
+ name: 'Греческий салат',
+ ingredients: ['помидоры', 'огурец', 'лук', 'оливки', 'сыр фета']
}, {
id: 'hawaiian-pizza',
- name: 'Hawaiian Pizza',
- ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple']
+ name: 'Гавайская пицца',
+ ingredients: ['тесто для пиццы', 'соус для пиццы', 'моцарелла', 'ветчина', 'ананас']
}, {
id: 'hummus',
- name: 'Hummus',
- ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini']
+ name: 'Хумус',
+ ingredients: ['нут', 'оливковое масло', 'зубчики чеснока', 'лимон', 'тахини']
}];
```
@@ -1026,7 +1028,7 @@ export const recipes = [{
-You can copy-paste the JSX from the outer `map` into a new `Recipe` component and return that JSX. Then you can change `recipe.name` to `name`, `recipe.id` to `id`, and so on, and pass them as props to the `Recipe`:
+Вы можете скопировать и вставить JSX из внешнего вызова map в новый компонент `Recipe` и вернуть этот JSX. Затем вы можете изменить `recipe.name` на `name`, `recipe.id` на `id` и т.д., и передать их в виде пропсов компоненту `Recipe`:
@@ -1051,7 +1053,7 @@ function Recipe({ id, name, ingredients }) {
export default function RecipeList() {
return (
-
Recipes
+
Рецепты
{recipes.map(recipe =>
)}
@@ -1063,51 +1065,51 @@ export default function RecipeList() {
```js data.js
export const recipes = [{
id: 'greek-salad',
- name: 'Greek Salad',
- ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta']
+ name: 'Греческий салат',
+ ingredients: ['помидоры', 'огурец', 'лук', 'оливки', 'сыр фета']
}, {
id: 'hawaiian-pizza',
- name: 'Hawaiian Pizza',
- ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple']
+ name: 'Гавайская пицца',
+ ingredients: ['тесто для пиццы', 'соус для пиццы', 'моцарелла', 'ветчина', 'ананас']
}, {
id: 'hummus',
- name: 'Hummus',
- ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini']
+ name: 'Хумус',
+ ingredients: ['нут', 'оливковое масло', 'зубчики чеснока', 'лимон', 'тахини']
}];
```
-Here, `` is a syntax shortcut saying "pass all properties of the `recipe` object as props to the `Recipe` component". You could also write each prop explicitly: ``.
+Здесь `` -- это сокращенный синтаксис, означающий "передайте все свойства объекта `recipe` как пропсы в компонент `Recipe`". Вы также можете явно задать каждый проп: ``.
-**Note that the `key` is specified on the `` itself rather than on the root `
` returned from `Recipe`.** This is because this `key` is needed directly within the context of the surrounding array. Previously, you had an array of `
`s so each of them needed a `key`, but now you have an array of ``s. In other words, when you extract a component, don't forget to leave the `key` outside the JSX you copy and paste.
+**Обратите внимание, что `key` указывается на самом компоненте ``, а не на корневом `
`, возвращаемом из `Recipe`.** Всё потому, что этот `key` необходим непосредственно в контексте окружающего массива. Ранее у вас был массив `
`, поэтому каждому из них требовался ключ, но теперь у вас есть массив ``. Другими словами, когда вы извлекаете компонент, не забудьте оставить ключ за пределами JSX, который вы копируете и вставляете.
-#### List with a separator {/*list-with-a-separator*/}
+#### Список с разделителем {/*list-with-a-separator*/}
-This example renders a famous haiku by Katsushika Hokusai, with each line wrapped in a `
` tag. Your job is to insert an `
` separator between each paragraph. Your resulting structure should look like this:
+Данный пример рендерит известное хокку Кацусики Хокусая, каждая строка обернута в тег `
`. Ваша задача -- вставить разделитель `
` между каждым параграфом. Ваша структура должна выглядеть так:
```js
-
I write, erase, rewrite
+
Я пишу, стираю, переписываю,
-
Erase again, and then
+
Снова стереть, а затем
-
A poppy blooms.
+
Цветет мак.
```
-A haiku only contains three lines, but your solution should work with any number of lines. Note that `` elements only appear *between* the `
` elements, not in the beginning or the end!
+Хокку содержит только три строки, но ваше решение должно работать с любым количеством строк. Обратите внимание, что элементы `
` должны быть *между* элементами `
`, а не в начале или в конце!
```js
const poem = {
lines: [
- 'I write, erase, rewrite',
- 'Erase again, and then',
- 'A poppy blooms.'
+ 'Я пишу, стираю, переписываю,',
+ 'Снова стереть, а затем',
+ 'Цветет мак.'
]
};
@@ -1141,33 +1143,33 @@ hr {
-(This is a rare case where index as a key is acceptable because a poem's lines will never reorder.)
+(Это один из редких случаев когда можно использовать индекс в качестве ключа, потому что строки стихотворения никогда не будут переупорядочиваться.)
-You'll either need to convert `map` to a manual loop, or use a fragment.
+Вам понадобится либо поменять `map` на обычный цикл, либо использовать фрагмент.
-You can write a manual loop, inserting `` and `
...
` into the output array as you go:
+Вы можете использовать обычный цикл, вставляя `` и `
...
` в массив для вывода по мере выполнения:
```js
const poem = {
lines: [
- 'I write, erase, rewrite',
- 'Erase again, and then',
- 'A poppy blooms.'
+ 'Я пишу, стираю, переписываю,',
+ 'Снова стереть, а затем',
+ 'Цветет мак.'
]
};
export default function Poem() {
let output = [];
- // Fill the output array
+ // Заполнение массива для вывода
poem.lines.forEach((line, i) => {
output.push(
@@ -1178,7 +1180,7 @@ export default function Poem() {
);
});
- // Remove the first
+ // Убираем первый
output.shift();
return (
@@ -1206,9 +1208,9 @@ hr {
-Using the original line index as a `key` doesn't work anymore because each separator and paragraph are now in the same array. However, you can give each of them a distinct key using a suffix, e.g. `key={i + '-text'}`.
+Использование исходного индекса строки в качестве ключа больше не работает, потому что теперь каждый разделитель и абзац находятся в одном и том же массиве. Однако вы можете присвоить каждому из них уникальный ключ с использованием суффикса, например, `key={i + '-text'}`.
-Alternatively, you could render a collection of fragments which contain `` and `
...
`. However, the `<>...>` shorthand syntax doesn't support passing keys, so you'd have to write `` explicitly:
+В качестве альтернативы, вы можете отрендерить коллекцию фрагментов, содержащих `` и `
...
`. Однако сокращенный синтаксис `<>...>` не поддерживает передачу ключей, поэтому вам придется явно использовать ``:
@@ -1217,9 +1219,9 @@ import { Fragment } from 'react';
const poem = {
lines: [
- 'I write, erase, rewrite',
- 'Erase again, and then',
- 'A poppy blooms.'
+ 'Я пишу, стираю, переписываю,',
+ 'Снова стереть, а затем',
+ 'Цветет мак.'
]
};
@@ -1254,7 +1256,7 @@ hr {
-Remember, fragments (often written as `<> >`) let you group JSX nodes without adding extra `
`s!
+Запомните, фрагменты (часто записываемые как `<> >`) позволяют группировать JSX-узлы без добавления дополнительных `
`!
diff --git a/src/content/learn/responding-to-events.md b/src/content/learn/responding-to-events.md
index 782b6c0f1..4450c4613 100644
--- a/src/content/learn/responding-to-events.md
+++ b/src/content/learn/responding-to-events.md
@@ -313,6 +313,12 @@ button { margin-right: 10px; }
Notice how the `App` component does not need to know *what* `Toolbar` will do with `onPlayMovie` or `onUploadImage`. That's an implementation detail of the `Toolbar`. Here, `Toolbar` passes them down as `onClick` handlers to its `Button`s, but it could later also trigger them on a keyboard shortcut. Naming props after app-specific interactions like `onPlayMovie` gives you the flexibility to change how they're used later.
+
+
+
+Make sure that you use the appropriate HTML tags for your event handlers. For example, to handle clicks, use [`