diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 87dcfdc73..b1ef428d0 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -11,18 +11,26 @@ jobs: analyze: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up node - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: '20.x' + cache: yarn + cache-dependency-path: yarn.lock - - name: Install dependencies - uses: bahmutov/npm-install@v1.7.10 + - name: Restore cached node_modules + uses: actions/cache@v4 + with: + path: "**/node_modules" + key: node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + + - name: Install deps + run: yarn install --frozen-lockfile - name: Restore next build - uses: actions/cache@v2 + uses: actions/cache@v4 id: restore-build-cache env: cache-name: cache-next-build @@ -41,7 +49,7 @@ jobs: run: npx -p nextjs-bundle-analysis@0.5.0 report - name: Upload bundle - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: path: .next/analyze/__bundle_analysis.json name: bundle_analysis.json @@ -73,7 +81,7 @@ jobs: run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare - name: Upload analysis comment - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: analysis_comment.txt path: .next/analyze/__bundle_analysis_comment.txt @@ -82,7 +90,7 @@ jobs: run: echo ${{ github.event.number }} > ./pr_number - name: Upload PR number - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: pr_number path: ./pr_number diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml new file mode 100644 index 000000000..ff2caa1bf --- /dev/null +++ b/.github/workflows/discord_notify.yml @@ -0,0 +1,21 @@ +name: Discord Notify + +on: + pull_request_target: + types: [ labeled ] + +jobs: + notify: + if: ${{ github.event.label.name == 'React Core Team' }} + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v6.0.0 + with: + webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.pull_request.user.login }} + embed-author-url: ${{ github.event.pull_request.user.html_url }} + embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }} + embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}' + embed-description: ${{ github.event.pull_request.body }} + embed-url: ${{ github.event.pull_request.html_url }} \ No newline at end of file diff --git a/.github/workflows/site_lint.yml b/.github/workflows/site_lint.yml index 34ca6d7b8..36f7642c9 100644 --- a/.github/workflows/site_lint.yml +++ b/.github/workflows/site_lint.yml @@ -14,14 +14,22 @@ jobs: name: Lint on node 20.x and ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Use Node.js 20.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20.x + cache: yarn + cache-dependency-path: yarn.lock - - name: Install deps and build (with cache) - uses: bahmutov/npm-install@v1.8.32 + - name: Restore cached node_modules + uses: actions/cache@v4 + with: + path: "**/node_modules" + key: node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + + - name: Install deps + run: yarn install --frozen-lockfile - name: Lint codebase run: yarn ci-check diff --git a/.gitignore b/.gitignore index d8bec488b..7bf71dbc5 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ yarn-error.log* # external fonts public/fonts/**/Optimistic_*.woff2 + +# rss +public/rss.xml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0e861af35..4c7e5ec74 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,6 +79,7 @@ Ignore this rule if you're specifically describing an experimental proposal. Mak - Use semicolons. - No space between function names and parens (`method() {}` not `method () {}`). - When in doubt, use the default style favored by [Prettier](https://prettier.io/playground/). +- Always capitalize React concepts such as Hooks, Effects, and Transitions. ### Highlighting diff --git a/README.md b/README.md index 966131db5..182192cb5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This repo contains the source code and documentation powering [react.dev](https: ### Prerequisites 1. Git -1. Node: any 12.x version starting with v12.0.0 or greater +1. Node: any version starting with v16.8.0 or greater 1. Yarn: See [Yarn website for installation instructions](https://yarnpkg.com/lang/en/docs/install/) 1. A fork of the repo (for any contributions) 1. A clone of the [react.dev repo](https://github.com/reactjs/react.dev) on your local machine diff --git a/TRANSLATION.md b/TRANSLATION.md index 61e11268c..b993bc4b9 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -118,6 +118,7 @@ Terminy z (?) przy sugestii są do przegadania. Jeśli wiesz, jakie powinno ich | cleanup function | funkcja czyszcząca | W kontekście `useEffect` | | client | klient | | | clients | klienty | Nie: klienci | +| commit | aktualizacja | W kontekście renderowania | | component state | stan komponentu | | | component wrapping | opakowywanie komponentu | | | concept | zagadnienie | | diff --git a/colors.js b/colors.js index acf8214ee..872f33cac 100644 --- a/colors.js +++ b/colors.js @@ -11,7 +11,7 @@ module.exports = { tertiary: '#5E687E', // gray-50 'tertiary-dark': '#99A1B3', // gray-30 link: '#087EA4', // blue-50 - 'link-dark': '#149ECA', // blue-40 + 'link-dark': '#58C4DC', // blue-40 syntax: '#EBECF0', // gray-10 wash: '#FFFFFF', 'wash-dark': '#23272F', // gray-90 @@ -23,6 +23,8 @@ module.exports = { 'border-dark': '#343A46', // gray-80 'secondary-button': '#EBECF0', // gray-10 'secondary-button-dark': '#404756', // gray-70 + brand: '#087EA4', // blue-40 + 'brand-dark': '#58C4DC', // blue-40 // Gray 'gray-95': '#16181D', diff --git a/package.json b/package.json index 274c2506e..ad9b9baa4 100644 --- a/package.json +++ b/package.json @@ -15,17 +15,19 @@ "prettier:diff": "yarn nit:source", "lint-heading-ids": "node scripts/headingIdLinter.js", "fix-headings": "node scripts/headingIdLinter.js --fix", - "ci-check": "npm-run-all prettier:diff --parallel lint tsc lint-heading-ids", + "ci-check": "npm-run-all prettier:diff --parallel lint tsc lint-heading-ids rss", "tsc": "tsc --noEmit", "start": "next start", "postinstall": "patch-package && (is-ci || husky install .husky)", - "check-all": "npm-run-all prettier lint:fix tsc" + "check-all": "npm-run-all prettier lint:fix tsc rss", + "rss": "node scripts/generateRss.js" }, "dependencies": { - "@codesandbox/sandpack-react": "2.13.1", - "@docsearch/css": "3.0.0-alpha.41", - "@docsearch/react": "3.0.0-alpha.41", + "@codesandbox/sandpack-react": "2.13.5", + "@docsearch/css": "^3.6.1", + "@docsearch/react": "^3.6.1", "@headlessui/react": "^1.7.0", + "@radix-ui/react-context-menu": "^2.1.5", "body-scroll-lock": "^3.1.3", "classnames": "^2.2.6", "date-fns": "^2.16.1", @@ -97,7 +99,7 @@ "webpack-bundle-analyzer": "^4.5.0" }, "engines": { - "node": "^16.8.0 || ^18.0.0 || ^19.0.0 || ^20.0.0" + "node": ">=16.8.0" }, "nextBundleAnalysis": { "budget": null, diff --git a/public/.well-known/atproto-did b/public/.well-known/atproto-did new file mode 100644 index 000000000..ad8b0a36b --- /dev/null +++ b/public/.well-known/atproto-did @@ -0,0 +1 @@ +did:plc:uorpbnp2q32vuvyeruwauyhe \ No newline at end of file diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png new file mode 100644 index 000000000..5de701e13 Binary files /dev/null and b/public/android-chrome-192x192.png differ diff --git a/public/android-chrome-384x384.png b/public/android-chrome-384x384.png new file mode 100644 index 000000000..f42a6776e Binary files /dev/null and b/public/android-chrome-384x384.png differ diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png new file mode 100644 index 000000000..2fdbf6902 Binary files /dev/null and b/public/android-chrome-512x512.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 000000000..baf1332a3 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 000000000..f9c2e67fe --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #2b5797 + + + diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 000000000..d24cb4f76 Binary files /dev/null and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 000000000..953ae4cc3 Binary files /dev/null and b/public/favicon-32x32.png differ diff --git a/public/favicon.ico b/public/favicon.ico index 38fd8641c..519b939a0 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon_old.ico b/public/favicon_old.ico new file mode 100644 index 000000000..20b59d440 Binary files /dev/null and b/public/favicon_old.ico differ diff --git a/public/images/brand/logo_dark.svg b/public/images/brand/logo_dark.svg new file mode 100644 index 000000000..265777fa3 --- /dev/null +++ b/public/images/brand/logo_dark.svg @@ -0,0 +1,12 @@ + + + React-Logo-Filled (1) + + + + + + + + + \ No newline at end of file diff --git a/public/images/brand/logo_light.svg b/public/images/brand/logo_light.svg new file mode 100644 index 000000000..bbe5a8994 --- /dev/null +++ b/public/images/brand/logo_light.svg @@ -0,0 +1,10 @@ + + + React-Logo-Filled (1) + + + + + + + \ No newline at end of file diff --git a/public/images/brand/wordmark_dark.svg b/public/images/brand/wordmark_dark.svg new file mode 100644 index 000000000..ec028ae21 --- /dev/null +++ b/public/images/brand/wordmark_dark.svg @@ -0,0 +1,15 @@ + + + Group + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/brand/wordmark_light.svg b/public/images/brand/wordmark_light.svg new file mode 100644 index 000000000..2de8f3cc7 --- /dev/null +++ b/public/images/brand/wordmark_light.svg @@ -0,0 +1,11 @@ + + + Group + + + + + + + + \ No newline at end of file diff --git a/public/images/docs/diagrams/prerender.dark.png b/public/images/docs/diagrams/prerender.dark.png new file mode 100644 index 000000000..1e7d67e13 Binary files /dev/null and b/public/images/docs/diagrams/prerender.dark.png differ diff --git a/public/images/docs/diagrams/prerender.png b/public/images/docs/diagrams/prerender.png new file mode 100644 index 000000000..ababa5493 Binary files /dev/null and b/public/images/docs/diagrams/prerender.png differ diff --git a/public/images/docs/diagrams/prewarm.dark.png b/public/images/docs/diagrams/prewarm.dark.png new file mode 100644 index 000000000..461406039 Binary files /dev/null and b/public/images/docs/diagrams/prewarm.dark.png differ diff --git a/public/images/docs/diagrams/prewarm.png b/public/images/docs/diagrams/prewarm.png new file mode 100644 index 000000000..f6ec1c49d Binary files /dev/null and b/public/images/docs/diagrams/prewarm.png differ diff --git a/public/images/team/jack-pope.jpg b/public/images/team/jack-pope.jpg new file mode 100644 index 000000000..601e5840e Binary files /dev/null and b/public/images/team/jack-pope.jpg differ diff --git a/public/images/team/lauren.jpg b/public/images/team/lauren.jpg index 1485cf8ff..26d46bd2f 100644 Binary files a/public/images/team/lauren.jpg and b/public/images/team/lauren.jpg differ diff --git a/public/images/team/lesiutin.jpg b/public/images/team/lesiutin.jpg new file mode 100644 index 000000000..edfc942e0 Binary files /dev/null and b/public/images/team/lesiutin.jpg differ diff --git a/public/images/uwu.png b/public/images/uwu.png new file mode 100644 index 000000000..a09d245ea Binary files /dev/null and b/public/images/uwu.png differ diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png new file mode 100644 index 000000000..d36e7ee9e Binary files /dev/null and b/public/mstile-150x150.png differ diff --git a/public/safari-pinned-tab.svg b/public/safari-pinned-tab.svg new file mode 100644 index 000000000..7e4874b2f --- /dev/null +++ b/public/safari-pinned-tab.svg @@ -0,0 +1,60 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 000000000..337446d52 --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "React", + "short_name": "React", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + } + ], + "theme_color": "#23272f", + "background_color": "#23272f", + "display": "standalone" +} diff --git a/scripts/generateRss.js b/scripts/generateRss.js new file mode 100644 index 000000000..e0f3d5561 --- /dev/null +++ b/scripts/generateRss.js @@ -0,0 +1,6 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ +const {generateRssFeed} = require('../src/utils/rss'); + +generateRssFeed(); diff --git a/src/components/ButtonLink.tsx b/src/components/ButtonLink.tsx index 15ab83f2b..23c971756 100644 --- a/src/components/ButtonLink.tsx +++ b/src/components/ButtonLink.tsx @@ -26,7 +26,8 @@ function ButtonLink({ className, 'active:scale-[.98] transition-transform inline-flex font-bold items-center outline-none focus:outline-none focus-visible:outline focus-visible:outline-link focus:outline-offset-2 focus-visible:dark:focus:outline-link-dark leading-snug', { - 'bg-link text-white hover:bg-opacity-80': type === 'primary', + 'bg-link text-white dark:bg-brand-dark dark:text-secondary hover:bg-opacity-80': + type === 'primary', 'text-primary dark:text-primary-dark shadow-secondary-button-stroke dark:shadow-secondary-button-stroke-dark hover:bg-gray-40/5 active:bg-gray-40/10 hover:dark:bg-gray-60/5 active:dark:bg-gray-60/10': type === 'secondary', 'text-lg py-3 rounded-full px-4 sm:px-6': size === 'lg', diff --git a/src/components/Icon/IconBsky.tsx b/src/components/Icon/IconBsky.tsx new file mode 100644 index 000000000..6645152dd --- /dev/null +++ b/src/components/Icon/IconBsky.tsx @@ -0,0 +1,24 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import {memo} from 'react'; + +export const IconBsky = memo(function IconBsky( + props +) { + return ( + + + + ); +}); diff --git a/src/components/Icon/IconCanary.tsx b/src/components/Icon/IconCanary.tsx index a7782b141..7f584fed7 100644 --- a/src/components/Icon/IconCanary.tsx +++ b/src/components/Icon/IconCanary.tsx @@ -4,29 +4,35 @@ import {memo} from 'react'; -export const IconCanary = memo( - function IconCanary({className, title}) { - return ( - - {title && {title}} - - - - - - - ); +export const IconCanary = memo< + JSX.IntrinsicElements['svg'] & {title?: string; size?: 's' | 'md'} +>(function IconCanary( + {className, title, size} = { + className: undefined, + title: undefined, + size: 'md', } -); +) { + return ( + + {title && {title}} + + + + + + + ); +}); diff --git a/src/components/Icon/IconRocket.tsx b/src/components/Icon/IconRocket.tsx new file mode 100644 index 000000000..457736c7c --- /dev/null +++ b/src/components/Icon/IconRocket.tsx @@ -0,0 +1,32 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import {memo} from 'react'; + +export const IconRocket = memo< + JSX.IntrinsicElements['svg'] & {title?: string; size?: 's' | 'md'} +>(function IconRocket({className, size = 'md'}) { + return ( + + ); +}); diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index 467664b4b..a8309825b 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -8,6 +8,7 @@ import cn from 'classnames'; import {ExternalLink} from 'components/ExternalLink'; import {IconFacebookCircle} from 'components/Icon/IconFacebookCircle'; import {IconTwitter} from 'components/Icon/IconTwitter'; +import {IconBsky} from 'components/Icon/IconBsky'; import {IconGitHub} from 'components/Icon/IconGitHub'; export function Footer() { @@ -283,7 +284,31 @@ export function Footer() {
- ©{new Date().getFullYear()} + Copyright © Meta Platforms, Inc +
+
{ + // @ts-ignore + window.__setUwu(false); + }}> + no uwu plz +
+
{ + // @ts-ignore + window.__setUwu(true); + }}> + uwu? +
+
+ Logo by + + @sawaratsuki1004 +
@@ -294,7 +319,7 @@ export function Footer() { Instalacja Opisywanie UI - Adding Interactivity + Dodawanie interaktywności Zarządzanie stanem @@ -346,6 +371,12 @@ export function Footer() { className={socialLinkClasses}> + + +
+
+ logo by @sawaratsuki1004 +
-

+

React

@@ -489,7 +501,15 @@ export function HomeContent() {

- +
+ logo by @sawaratsuki1004 +
+
Welcome to the
React community @@ -1620,7 +1640,7 @@ function Thumbnail({video}) {
- + React Conf
diff --git a/src/components/Layout/Page.tsx b/src/components/Layout/Page.tsx index ee3c899d0..24d379589 100644 --- a/src/components/Layout/Page.tsx +++ b/src/components/Layout/Page.tsx @@ -8,19 +8,19 @@ import {useRouter} from 'next/router'; import {SidebarNav} from './SidebarNav'; import {Footer} from './Footer'; import {Toc} from './Toc'; -import SocialBanner from '../SocialBanner'; +// import SocialBanner from '../SocialBanner'; import {DocsPageFooter} from 'components/DocsFooter'; import {Seo} from 'components/Seo'; -import ButtonLink from 'components/ButtonLink'; -import {IconNavArrow} from 'components/Icon/IconNavArrow'; import PageHeading from 'components/PageHeading'; import {getRouteMeta} from './getRouteMeta'; import {TocContext} from '../MDX/TocContext'; +import {Languages, LanguagesContext} from '../MDX/LanguagesContext'; import type {TocItem} from 'components/MDX/TocContext'; import type {RouteItem} from 'components/Layout/getRouteMeta'; import {HomeContent} from './HomeContent'; import {TopNav} from './TopNav'; import cn from 'classnames'; +import Head from 'next/head'; import(/* webpackPrefetch: true */ '../MDX/CodeBlock/CodeBlock'); @@ -35,9 +35,17 @@ interface PageProps { description?: string; }; section: 'learn' | 'reference' | 'community' | 'blog' | 'home' | 'unknown'; + languages?: Languages | null; } -export function Page({children, toc, routeTree, meta, section}: PageProps) { +export function Page({ + children, + toc, + routeTree, + meta, + section, + languages = null, +}: PageProps) { const {asPath} = useRouter(); const cleanedPath = asPath.split(/[\?\#]/)[0]; const {route, nextRoute, prevRoute, breadcrumbs, order} = getRouteMeta( @@ -74,7 +82,11 @@ export function Page({children, toc, routeTree, meta, section}: PageProps) { 'max-w-7xl mx-auto', section === 'blog' && 'lg:flex lg:flex-col lg:items-center' )}> - {children} + + + {children} + +
{!isBlogIndex && ( - + {(isHomePage || isBlogIndex) && ( + + + + )} + {/**/} {!isHomePage && (
- { -
- } - {showSurvey && ( - <> -
-

- How do you like these docs? -

-
- - Take our survey! - - -
-
-
- - )} +
)}
{title}{' '} - {canary && ( + {version === 'major' && ( + + React 19 + + )} + {version === 'canary' && ( )}
diff --git a/src/components/Layout/Sidebar/SidebarRouteTree.tsx b/src/components/Layout/Sidebar/SidebarRouteTree.tsx index a9fa575b5..54f02b925 100644 --- a/src/components/Layout/Sidebar/SidebarRouteTree.tsx +++ b/src/components/Layout/Sidebar/SidebarRouteTree.tsx @@ -10,6 +10,7 @@ import {SidebarLink} from './SidebarLink'; import {useCollapse} from 'react-collapsed'; import usePendingRoute from 'hooks/usePendingRoute'; import type {RouteItem} from 'components/Layout/getRouteMeta'; +import {siteConfig} from 'siteConfig'; interface SidebarRouteTreeProps { isForceExpanded: boolean; @@ -86,7 +87,7 @@ export function SidebarRouteTree({ path, title, routes, - canary, + version, heading, hasSectionHeader, sectionHeader, @@ -120,7 +121,7 @@ export function SidebarRouteTree({ selected={selected} level={level} title={title} - canary={canary} + version={version} isExpanded={isExpanded} hideArrow={isForceExpanded} /> @@ -144,14 +145,18 @@ export function SidebarRouteTree({ selected={selected} level={level} title={title} - canary={canary} + version={version} /> ); } if (hasSectionHeader) { + let sectionHeaderText = + sectionHeader != null + ? sectionHeader.replace('{{version}}', siteConfig.version) + : ''; return ( - + {index !== 0 && (
  • - {sectionHeader} + {sectionHeaderText} ); diff --git a/src/components/Layout/TopNav/BrandMenu.tsx b/src/components/Layout/TopNav/BrandMenu.tsx new file mode 100644 index 000000000..3bd8776f2 --- /dev/null +++ b/src/components/Layout/TopNav/BrandMenu.tsx @@ -0,0 +1,145 @@ +import * as ContextMenu from '@radix-ui/react-context-menu'; +import {IconCopy} from 'components/Icon/IconCopy'; +import {IconDownload} from 'components/Icon/IconDownload'; +import {IconNewPage} from 'components/Icon/IconNewPage'; +import {ExternalLink} from 'components/ExternalLink'; +import {IconClose} from '../../Icon/IconClose'; + +function MenuItem({ + children, + onSelect, +}: { + children: React.ReactNode; + onSelect?: () => void; +}) { + return ( + + {children} + + ); +} + +function DownloadMenuItem({ + fileName, + href, + children, +}: { + fileName: string; + href: string; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} + +export default function BrandMenu({children}: {children: React.ReactNode}) { + return ( + + + {children} + + + + + Dark Mode + + + + + + Logo SVG + + + + + + Wordmark SVG + + { + await navigator.clipboard.writeText('#58C4DC'); + }}> + + + + Copy dark mode color + + + Light Mode + + + + + + Logo SVG + + + + + + Wordmark SVG + + { + await navigator.clipboard.writeText('#087EA4'); + }}> + + + + Copy light mode color + +
    + + + uwu + + { + // @ts-ignore + window.__setUwu(false); + }}> + + + + Turn off + + + + + + Logo PNG + + + + + + + + Logo by @sawaratsuki1004 + + +
    +
    +
    +
    + ); +} diff --git a/src/components/Layout/TopNav/TopNav.tsx b/src/components/Layout/TopNav/TopNav.tsx index b6e276ff7..cc5c654e3 100644 --- a/src/components/Layout/TopNav/TopNav.tsx +++ b/src/components/Layout/TopNav/TopNav.tsx @@ -10,6 +10,7 @@ import { startTransition, Suspense, } from 'react'; +import Image from 'next/image'; import * as React from 'react'; import cn from 'classnames'; import NextLink from 'next/link'; @@ -24,6 +25,8 @@ import {Logo} from '../../Logo'; import {Feedback} from '../Feedback'; import {SidebarRouteTree} from '../Sidebar'; import type {RouteItem} from '../getRouteMeta'; +import {siteConfig} from 'siteConfig'; +import BrandMenu from './BrandMenu'; declare global { interface Window { @@ -77,6 +80,19 @@ const lightIcon = ( ); +const languageIcon = ( + + + +); + const githubIcon = ( (null); const {asPath} = useRouter(); - const [isScrolled, setIsScrolled] = useState(false); // HACK. Fix up the data structures instead. if ((routeTree as any).routes.length === 1) { @@ -154,18 +171,18 @@ export default function TopNav({ // While the overlay is open, disable body scroll. useEffect(() => { - if (isOpen) { + if (isMenuOpen) { const preferredScrollParent = scrollParentRef.current!; disableBodyScroll(preferredScrollParent); return () => enableBodyScroll(preferredScrollParent); } else { return undefined; } - }, [isOpen]); + }, [isMenuOpen]); // Close the overlay on any navigation. useEffect(() => { - setIsOpen(false); + setIsMenuOpen(false); }, [asPath]); // Also close the overlay if the window gets resized past mobile layout. @@ -175,7 +192,7 @@ export default function TopNav({ function closeIfNeeded() { if (!media.matches) { - setIsOpen(false); + setIsMenuOpen(false); } } @@ -204,7 +221,6 @@ export default function TopNav({ return () => observer.disconnect(); }, []); - const [showSearch, setShowSearch] = useState(false); const onOpenSearch = useCallback(() => { startTransition(() => { setShowSearch(true); @@ -224,39 +240,63 @@ export default function TopNav({
    - {isOpen && ( + {isMenuOpen && (
  • ); } @@ -304,7 +307,7 @@ export default function PackingList() { function Item({ name, isPacked }) { return (
  • - {name} {isPacked ? '✔' : '❌'} + {name} {isPacked ? '✅' : '❌'}
  • ); } @@ -610,7 +613,7 @@ We hope that this approach will make the API reference useful not only as a way ## What's next? {/*whats-next*/} -That's a wrap for our little tour! Have a look around the new website, see what you like or don't like, and keep the feedback coming in the [anonymous survey](https://www.surveymonkey.co.uk/r/PYRPF3X) or in our [issue tracker](https://github.com/reactjs/reactjs.org/issues). +That's a wrap for our little tour! Have a look around the new website, see what you like or don't like, and keep the feedback coming in our [issue tracker](https://github.com/reactjs/react.dev/issues). We acknowledge this project has taken a long time to ship. We wanted to maintain a high quality bar that the React community deserves. While writing these docs and creating all of the examples, we found mistakes in some of our own explanations, bugs in React, and even gaps in the React design that we are now working to address. We hope that the new documentation will help us hold React itself to a higher bar in the future. diff --git a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md index 1f6b911e1..aeb677f31 100644 --- a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md +++ b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md @@ -1,5 +1,8 @@ --- title: "React Labs: What We've Been Working On – March 2023" +author: Joseph Savona, Josh Story, Lauren Tan, Mengdi Chen, Samuel Susla, Sathya Gunasekaran, Sebastian Markbage, and Andrew Clark +date: 2023/03/22 +description: In React Labs posts, we write about projects in active research and development. We've made significant progress on them since our last update, and we'd like to share what we learned. --- March 22, 2023 by [Joseph Savona](https://twitter.com/en_JS), [Josh Story](https://twitter.com/joshcstory), [Lauren Tan](https://twitter.com/potetotes), [Mengdi Chen](https://twitter.com/mengdi_en), [Samuel Susla](https://twitter.com/SamuelSusla), [Sathya Gunasekaran](https://twitter.com/_gsathya), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Andrew Clark](https://twitter.com/acdlite) diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md index 81da3fd00..19d9960b0 100644 --- a/src/content/blog/2023/05/03/react-canaries.md +++ b/src/content/blog/2023/05/03/react-canaries.md @@ -1,5 +1,8 @@ --- title: "React Canaries: Enabling Incremental Feature Rollout Outside Meta" +author: Dan Abramov, Sophie Alpert, Rick Hanlon, Sebastian Markbage, and Andrew Clark +date: 2023/05/03 +description: 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. --- 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) diff --git a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md index 03fc85c37..fee21f4ec 100644 --- a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md +++ b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md @@ -1,5 +1,8 @@ --- title: "React Labs: What We've Been Working On – February 2024" +author: Joseph Savona, Ricky Hanlon, Andrew Clark, Matt Carroll, and Dan Abramov +date: 2024/02/15 +description: In React Labs posts, we write about projects in active research and development. We’ve made significant progress since our last update, and we’d like to share our progress. --- February 15, 2024 by [Joseph Savona](https://twitter.com/en_JS), [Ricky Hanlon](https://twitter.com/rickhanlonii), [Andrew Clark](https://twitter.com/acdlite), [Matt Carroll](https://twitter.com/mattcarrollcode), and [Dan Abramov](https://twitter.com/dan_abramov). @@ -52,7 +55,7 @@ We refer to this broader collection of features as simply "Actions". Actions all ``` -The `action` function can operate synchronously or asynchronously. You can define them on the client side using standard JavaScript or on the server with the [`'use server'`](/reference/react/use-server) directive. When using an action, React will manage the life cycle of the data submission for you, providing hooks like [`useFormStatus`](/reference/react-dom/hooks/useFormStatus), and [`useFormState`](/reference/react-dom/hooks/useFormState) to access the current state and response of the form action. +The `action` function can operate synchronously or asynchronously. You can define them on the client side using standard JavaScript or on the server with the [`'use server'`](/reference/rsc/use-server) directive. When using an action, React will manage the life cycle of the data submission for you, providing hooks like [`useFormStatus`](/reference/react-dom/hooks/useFormStatus), and [`useActionState`](/reference/react/useActionState) to access the current state and response of the form action. By default, Actions are submitted within a [transition](/reference/react/useTransition), keeping the current page interactive while the action is processing. Since Actions support async functions, we've also added the ability to use `async/await` in transitions. This allows you to show pending UI with the `isPending` state of a transition when an async request like `fetch` starts, and show the pending UI all the way through the update being applied. @@ -72,13 +75,13 @@ Canaries are a change to the way we develop React. Previously, features would be React Server Components, Asset Loading, Document Metadata, and Actions have all landed in the React Canary, and we've added docs for these features on react.dev: -- **Directives**: [`"use client"`](/reference/react/use-client) and [`"use server"`](/reference/react/use-server) are bundler features designed for full-stack React frameworks. They mark the "split points" between the two environments: `"use client"` instructs the bundler to generate a ` +``` + +### Libraries depending on React internals may block upgrades {/*libraries-depending-on-react-internals-may-block-upgrades*/} + +This release includes changes to React internals that may impact libraries that ignore our pleas to not use internals like `SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`. These changes are necessary to land improvements in React 19, and will not break libraries that follow our guidelines. + +Based on our [Versioning Policy](https://react.dev/community/versioning-policy#what-counts-as-a-breaking-change), these updates are not listed as breaking changes, and we are not including docs for how to upgrade them. The recommendation is to remove any code that depends on internals. + +To reflect the impact of using internals, we have renamed the `SECRET_INTERNALS` suffix to: + +`_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE` + +In the future we will more aggressively block accessing internals from React to discourage usage and ensure users are not blocked from upgrading. + +## TypeScript changes {/*typescript-changes*/} + +### Removed deprecated TypeScript types {/*removed-deprecated-typescript-types*/} + +We've cleaned up the TypeScript types based on the removed APIs in React 19. Some of the removed have types been moved to more relevant packages, and others are no longer needed to describe React's behavior. + + +We've published [`types-react-codemod`](https://github.com/eps1lon/types-react-codemod/) to migrate most type related breaking changes: + +```bash +npx types-react-codemod@latest preset-19 ./path-to-app +``` + +If you have a lot of unsound access to `element.props`, you can run this additional codemod: + +```bash +npx types-react-codemod@latest react-element-default-any-props ./path-to-your-react-ts-files +``` + + + +Check out [`types-react-codemod`](https://github.com/eps1lon/types-react-codemod/) for a list of supported replacements. If you feel a codemod is missing, it can be tracked in the [list of missing React 19 codemods](https://github.com/eps1lon/types-react-codemod/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22React+19%22+label%3Aenhancement). + + +### `ref` cleanups required {/*ref-cleanup-required*/} + +_This change is included in the `react-19` codemod preset as [`no-implicit-ref-callback-return +`](https://github.com/eps1lon/types-react-codemod/#no-implicit-ref-callback-return)._ + +Due to the introduction of ref cleanup functions, returning anything else from a ref callback will now be rejected by TypeScript. The fix is usually to stop using implicit returns: + +```diff [[1, 1, "("], [1, 1, ")"], [2, 2, "{", 15], [2, 2, "}", 1]] +-
    (instance = current)} /> ++
    {instance = current}} /> +``` + +The original code returned the instance of the `HTMLDivElement` and TypeScript wouldn't know if this was supposed to be a cleanup function or not. + +### `useRef` requires an argument {/*useref-requires-argument*/} + +_This change is included in the `react-19` codemod preset as [`refobject-defaults`](https://github.com/eps1lon/types-react-codemod/#refobject-defaults)._ + +A long-time complaint of how TypeScript and React work has been `useRef`. We've changed the types so that `useRef` now requires an argument. This significantly simplifies its type signature. It'll now behave more like `createContext`. + +```ts +// @ts-expect-error: Expected 1 argument but saw none +useRef(); +// Passes +useRef(undefined); +// @ts-expect-error: Expected 1 argument but saw none +createContext(); +// Passes +createContext(undefined); +``` + +This now also means that all refs are mutable. You'll no longer hit the issue where you can't mutate a ref because you initialised it with `null`: + +```ts +const ref = useRef(null); + +// Cannot assign to 'current' because it is a read-only property +ref.current = 1; +``` + +`MutableRef` is now deprecated in favor of a single `RefObject` type which `useRef` will always return: + +```ts +interface RefObject { + current: T +} + +declare function useRef: RefObject +``` + +`useRef` still has a convenience overload for `useRef(null)` that automatically returns `RefObject`. To ease migration due to the required argument for `useRef`, a convenience overload for `useRef(undefined)` was added that automatically returns `RefObject`. + +Check out [[RFC] Make all refs mutable](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/64772) for prior discussions about this change. + +### Changes to the `ReactElement` TypeScript type {/*changes-to-the-reactelement-typescript-type*/} + +_This change is included in the [`react-element-default-any-props`](https://github.com/eps1lon/types-react-codemod#react-element-default-any-props) codemod._ + +The `props` of React elements now default to `unknown` instead of `any` if the element is typed as `ReactElement`. This does not affect you if you pass a type argument to `ReactElement`: + +```ts +type Example2 = ReactElement<{ id: string }>["props"]; +// ^? { id: string } +``` + +But if you relied on the default, you now have to handle `unknown`: + +```ts +type Example = ReactElement["props"]; +// ^? Before, was 'any', now 'unknown' +``` + +You should only need it if you have a lot of legacy code relying on unsound access of element props. Element introspection only exists as an escape hatch, and you should make it explicit that your props access is unsound via an explicit `any`. + +### The JSX namespace in TypeScript {/*the-jsx-namespace-in-typescript*/} +This change is included in the `react-19` codemod preset as [`scoped-jsx`](https://github.com/eps1lon/types-react-codemod#scoped-jsx) + +A long-time request is to remove the global `JSX` namespace from our types in favor of `React.JSX`. This helps prevent pollution of global types which prevents conflicts between different UI libraries that leverage JSX. + +You'll now need to wrap module augmentation of the JSX namespace in `declare module "....": + +```diff +// global.d.ts ++ declare module "react" { + namespace JSX { + interface IntrinsicElements { + "my-element": { + myElementProps: string; + }; + } + } ++ } +``` + +The exact module specifier depends on the JSX runtime you specified in the `compilerOptions` of your `tsconfig.json`: + +- For `"jsx": "react-jsx"` it would be `react/jsx-runtime`. +- For `"jsx": "react-jsxdev"` it would be `react/jsx-dev-runtime`. +- For `"jsx": "react"` and `"jsx": "preserve"` it would be `react`. + +### Better `useReducer` typings {/*better-usereducer-typings*/} + +`useReducer` now has improved type inference thanks to [@mfp22](https://github.com/mfp22). + +However, this required a breaking change where `useReducer` doesn't accept the full reducer type as a type parameter but instead either needs none (and rely on contextual typing) or needs both the state and action type. + +The new best practice is _not_ to pass type arguments to `useReducer`. +```diff +- useReducer>(reducer) ++ useReducer(reducer) +``` +This may not work in edge cases where you can explicitly type the state and action, by passing in the `Action` in a tuple: +```diff +- useReducer>(reducer) ++ useReducer(reducer) +``` +If you define the reducer inline, we encourage to annotate the function parameters instead: +```diff +- useReducer>((state, action) => state) ++ useReducer((state: State, action: Action) => state) +``` +This is also what you'd also have to do if you move the reducer outside of the `useReducer` call: + +```ts +const reducer = (state: State, action: Action) => state; +``` + +## Changelog {/*changelog*/} + +### Other breaking changes {/*other-breaking-changes*/} + +- **react-dom**: Error for javascript URLs in `src` and `href` [#26507](https://github.com/facebook/react/pull/26507) +- **react-dom**: Remove `errorInfo.digest` from `onRecoverableError` [#28222](https://github.com/facebook/react/pull/28222) +- **react-dom**: Remove `unstable_flushControlled` [#26397](https://github.com/facebook/react/pull/26397) +- **react-dom**: Remove `unstable_createEventHandle` [#28271](https://github.com/facebook/react/pull/28271) +- **react-dom**: Remove `unstable_renderSubtreeIntoContainer` [#28271](https://github.com/facebook/react/pull/28271) +- **react-dom**: Remove `unstable_runWithPriority` [#28271](https://github.com/facebook/react/pull/28271) +- **react-is**: Remove deprecated methods from `react-is` [28224](https://github.com/facebook/react/pull/28224) + +### Other notable changes {/*other-notable-changes*/} + +- **react**: Batch sync, default and continuous lanes [#25700](https://github.com/facebook/react/pull/25700) +- **react**: Don't prerender siblings of suspended component [#26380](https://github.com/facebook/react/pull/26380) +- **react**: Detect infinite update loops caused by render phase updates [#26625](https://github.com/facebook/react/pull/26625) +- **react-dom**: Transitions in popstate are now synchronous [#26025](https://github.com/facebook/react/pull/26025) +- **react-dom**: Remove layout effect warning during SSR [#26395](https://github.com/facebook/react/pull/26395) +- **react-dom**: Warn and don’t set empty string for src/href (except anchor tags) [#28124](https://github.com/facebook/react/pull/28124) + +For a full list of changes, please see the [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md#1900-december-5-2024). + +--- + +Thanks to [Andrew Clark](https://twitter.com/acdlite), [Eli White](https://twitter.com/Eli_White), [Jack Pope](https://github.com/jackpope), [Jan Kassens](https://github.com/kassens), [Josh Story](https://twitter.com/joshcstory), [Matt Carroll](https://twitter.com/mattcarrollcode), [Noah Lemen](https://twitter.com/noahlemen), [Sophie Alpert](https://twitter.com/sophiebits), and [Sebastian Silbermann](https://twitter.com/sebsilbermann) for reviewing and editing this post. diff --git a/src/content/blog/2024/05/22/react-conf-2024-recap.md b/src/content/blog/2024/05/22/react-conf-2024-recap.md new file mode 100644 index 000000000..bc77f4bbb --- /dev/null +++ b/src/content/blog/2024/05/22/react-conf-2024-recap.md @@ -0,0 +1,124 @@ +--- +title: "React Conf 2024 Recap" +author: Ricky Hanlon +date: 2024/05/22 +description: Last week we hosted React Conf 2024, a two-day conference in Henderson, Nevada where 700+ attendees gathered in-person to discuss the latest in UI engineering. In this post, we'll summarize the talks and announcements from the event. +--- + +May 22, 2024 by [Ricky Hanlon](https://twitter.com/rickhanlonii). + +--- + + + +Last week we hosted React Conf 2024, a two-day conference in Henderson, Nevada where 700+ attendees gathered in-person to discuss the latest in UI engineering. This was our first in-person conference since 2019, and we were thrilled to be able to bring the community together again. + + + +--- + +At React Conf 2024, we announced the [React 19 RC](/blog/2024/12/05/react-19), the [React Native New Architecture Beta](https://github.com/reactwg/react-native-new-architecture/discussions/189), and an experimental release of the [React Compiler](/learn/react-compiler). The community also took the stage to announce [React Router v7](https://remix.run/blog/merging-remix-and-react-router), [Universal Server Components](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=20765s) in Expo Router, React Server Components in [RedwoodJS](https://redwoodjs.com/blog/rsc-now-in-redwoodjs), and much more. + +The entire [day 1](https://www.youtube.com/watch?v=T8TZQ6k4SLE) and [day 2](https://www.youtube.com/watch?v=0ckOUBiuxVY) streams are available online. In this post, we'll summarize the talks and announcements from the event. + +## Day 1 {/*day-1*/} + +_[Watch the full day 1 stream here.](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=973s)_ + +To kick off day 1, Meta CTO [Andrew "Boz" Bosworth](https://www.threads.net/@boztank) shared a welcome message followed by an introduction by [Seth Webster](https://twitter.com/sethwebster), who manages the React Org at Meta, and our MC [Ashley Narcisse](https://twitter.com/_darkfadr). + +In the day 1 keynote, [Joe Savona](https://twitter.com/en_JS) shared our goals and vision for React to make it easy for anyone to build great user experiences. [Lauren Tan](https://twitter.com/potetotes) followed with a State of React, where she shared that React was downloaded over 1 billion times in 2023, and that 37% of new developers learn to program with React. Finally, she highlighted the work of the React community to make React, React. + +For more, check out these talks from the community later in the conference: + +- [Vanilla React](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=5542s) by [Ryan Florence](https://twitter.com/ryanflorence) +- [React Rhythm & Blues](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=12728s) by [Lee Robinson](https://twitter.com/leeerob) +- [RedwoodJS, now with React Server Components](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=26815s) by [Amy Dutton](https://twitter.com/selfteachme) +- [Introducing Universal React Server Components in Expo Router](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=20765s) by [Evan Bacon](https://twitter.com/Baconbrix) + +Next in the keynote, [Josh Story](https://twitter.com/joshcstory) and [Andrew Clark](https://twitter.com/acdlite) shared new features coming in React 19, and announced the React 19 RC which is ready for testing in production. Check out all the features in the [React 19 release post](/blog/2024/12/05/react-19), and see these talks for deep dives on the new features: + +- [What's new in React 19](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=8880s) by [Lydia Hallie](https://twitter.com/lydiahallie) +- [React Unpacked: A Roadmap to React 19](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=10112s) by [Sam Selikoff](https://twitter.com/samselikoff) +- [React 19 Deep Dive: Coordinating HTML](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=24916s) by [Josh Story](https://twitter.com/joshcstory) +- [Enhancing Forms with React Server Components](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=25280s) by [Aurora Walberg Scharff](https://twitter.com/aurorascharff) +- [React for Two Computers](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=18825s) by [Dan Abramov](https://twitter.com/dan_abramov2) +- [And Now You Understand React Server Components](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=11256s) by [Kent C. Dodds](https://twitter.com/kentcdodds) + +Finally, we ended the keynote with [Joe Savona](https://twitter.com/en_JS), [Sathya Gunasekaran](https://twitter.com/_gsathya), and [Mofei Zhang](https://twitter.com/zmofei) announcing that the React Compiler is now [Open Source](https://github.com/facebook/react/pull/29061), and sharing an experimental version of the React Compiler to try out. + +For more information on using the Compiler and how it works, check out [the docs](/learn/react-compiler) and these talks: + +- [Forget About Memo](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=12020s) by [Lauren Tan](https://twitter.com/potetotes) +- [React Compiler Deep Dive](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=9313s) by [Sathya Gunasekaran](https://twitter.com/_gsathya) and [Mofei Zhang](https://twitter.com/zmofei) + +Watch the full day 1 keynote here: + + + +## Day 2 {/*day-2*/} + +_[Watch the full day 2 stream here.](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=1720s)_ + +To kick off day 2, [Seth Webster](https://twitter.com/sethwebster) shared a welcome message, followed by a Thank You from [Eli White](https://x.com/Eli_White) and an introduction by our Chief Vibes Officer [Ashley Narcisse](https://twitter.com/_darkfadr). + +In the day 2 keynote, [Nicola Corti](https://twitter.com/cortinico) shared the State of React Native, including 78 million downloads in 2023. He also highlighted apps using React Native including 2000+ screens used inside of Meta; the product details page in Facebook Marketplace, which is visited more than 2 billion times per day; and part of the Microsoft Windows Start Menu and some features in almost every Microsoft Office product across mobile and desktop. + +Nicola also highlighted all the work the community does to support React Native including libraries, frameworks, and multiple platforms. For more, check out these talks from the community: + +- [Extending React Native beyond Mobile and Desktop Apps](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=5798s) by [Chris Traganos](https://twitter.com/chris_trag) and [Anisha Malde](https://twitter.com/anisha_malde) +- [Spatial computing with React](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=22525s) by [Michał Pierzchała](https://twitter.com/thymikee) + +[Riccardo Cipolleschi](https://twitter.com/cipolleschir) continued the day 2 keynote by announcing that the React Native New Architecture is now in Beta and ready for apps to adopt in production. He shared new features and improvements in the new architecture, and shared the roadmap for the future of React Native. For more check out: + +- [Cross Platform React](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=26569s) by [Olga Zinoveva](https://github.com/SlyCaptainFlint) and [Naman Goel](https://twitter.com/naman34) + +Next in the keynote, Nicola announced that we are now recommending starting with a framework like Expo for all new apps created with React Native. With the change, he also announced a new React Native homepage and new Getting Started docs. You can view the new Getting Started guide in the [React Native docs](https://reactnative.dev/docs/next/environment-setup). + +Finally, to end the keynote, [Kadi Kraman](https://twitter.com/kadikraman) shared the latest features and improvements in Expo, and how to get started developing with React Native using Expo. + +Watch the full day 2 keynote here: + + + +## Q&A {/*q-and-a*/} + +The React and React Native teams also ended each day with a Q&A session: + +- [React Q&A](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=27518s) hosted by [Michael Chan](https://twitter.com/chantastic) +- [React Native Q&A](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=27935s) hosted by [Jamon Holmgren](https://twitter.com/jamonholmgren) + +## And more... {/*and-more*/} + +We also heard talks on accessibility, error reporting, css, and more: + +- [Demystifying accessibility in React apps](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=20655s) by [Kateryna Porshnieva](https://twitter.com/krambertech) +- [Pigment CSS, CSS in the server component age](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=21696s) by [Olivier Tassinari](https://twitter.com/olivtassinari) +- [Real-time React Server Components](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=24070s) by [Sunil Pai](https://twitter.com/threepointone) +- [Let's break React Rules](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=25862s) by [Charlotte Isambert](https://twitter.com/c_isambert) +- [Solve 100% of your errors](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=19881s) by [Ryan Albrecht](https://github.com/ryan953) + +## Thank you {/*thank-you*/} + +Thank you to all the staff, speakers, and participants who made React Conf 2024 possible. There are too many to list, but we want to thank a few in particular. + +Thank you to [Barbara Markiewicz](https://twitter.com/barbara_markie), the team at [Callstack](https://www.callstack.com/), and our React Team Developer Advocate [Matt Carroll](https://twitter.com/mattcarrollcode) for helping to plan the entire event; and to [Sunny Leggett](https://zeroslopeevents.com/about) and everyone from [Zero Slope](https://zeroslopeevents.com) for helping to organize the event. + +Thank you [Ashley Narcisse](https://twitter.com/_darkfadr) for being our MC and Chief Vibes Officer; and to [Michael Chan](https://twitter.com/chantastic) and [Jamon Holmgren](https://twitter.com/jamonholmgren) for hosting the Q&A sessions. + +Thank you [Seth Webster](https://twitter.com/sethwebster) and [Eli White](https://x.com/Eli_White) for welcoming us each day and providing direction on structure and content; and to [Tom Occhino](https://twitter.com/tomocchino) for joining us with a special message during the after-party. + +Thank you [Ricky Hanlon](https://www.youtube.com/watch?v=FxTZL2U-uKg&t=1263s) for providing detailed feedback on talks, working on slide designs, and generally filling in the gaps to sweat the details. + +Thank you [Callstack](https://www.callstack.com/) for building the conference website; and to [Kadi Kraman](https://twitter.com/kadikraman) and the [Expo](https://expo.dev/) team for building the conference mobile app. + +Thank you to all the sponsors who made the event possible: [Remix](https://remix.run/), [Amazon](https://developer.amazon.com/apps-and-games?cmp=US_2024_05_3P_React-Conf-2024&ch=prtnr&chlast=prtnr&pub=ref&publast=ref&type=org&typelast=org), [MUI](https://mui.com/), [Sentry](https://sentry.io/for/react/?utm_source=sponsored-conf&utm_medium=sponsored-event&utm_campaign=frontend-fy25q2-evergreen&utm_content=logo-reactconf2024-learnmore), [Abbott](https://www.jobs.abbott/software), [Expo](https://expo.dev/), [RedwoodJS](https://redwoodjs.com/), and [Vercel](https://vercel.com). + +Thank you to the AV Team for the visuals, stage, and sound; and to the Westin Hotel for hosting us. + +Thank you to all the speakers who shared their knowledge and experiences with the community. + +Finally, thank you to everyone who attended in person and online to show what makes React, React. React is more than a library, it is a community, and it was inspiring to see everyone come together to share and learn together. + +See you next time! + diff --git a/src/content/blog/2024/10/21/react-compiler-beta-release.md b/src/content/blog/2024/10/21/react-compiler-beta-release.md new file mode 100644 index 000000000..f5a870b22 --- /dev/null +++ b/src/content/blog/2024/10/21/react-compiler-beta-release.md @@ -0,0 +1,126 @@ +--- +title: "React Compiler Beta Release" +author: Lauren Tan +date: 2024/10/21 +description: At React Conf 2024, we announced the experimental release of React Compiler, a build-time tool that optimizes your React app through automatic memoization. In this post, we want to share what's next for open source, and our progress on the compiler. + +--- + +October 21, 2024 by [Lauren Tan](https://twitter.com/potetotes). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler Beta today, so that early adopters and library maintainers can try it and provide feedback. +2. We're officially supporting React Compiler for apps on React 17+, through an optional `react-compiler-runtime` package. +3. We're opening up public membership of the [React Compiler Working Group](https://github.com/reactwg/react-compiler) to prepare the community for gradual adoption of the compiler. + +--- + +At [React Conf 2024](/blog/2024/05/22/react-conf-2024-recap), we announced the experimental release of React Compiler, a build-time tool that optimizes your React app through automatic memoization. [You can find an introduction to React Compiler here](/learn/react-compiler). + +Since the first release, we've fixed numerous bugs reported by the React community, received several high quality bug fixes and contributions[^1] to the compiler, made the compiler more resilient to the broad diversity of JavaScript patterns, and have continued to roll out the compiler more widely at Meta. + +In this post, we want to share what's next for React Compiler. + +## Try React Compiler Beta today {/*try-react-compiler-beta-today*/} + +At [React India 2024](https://www.youtube.com/watch?v=qd5yk2gxbtg), we shared an update on React Compiler. Today, we are excited to announce a new Beta release of React Compiler and ESLint plugin. New betas are published to npm using the `@beta` tag. + +To install React Compiler Beta: + + +npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta + + +Or, if you're using Yarn: + + +yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta + + +You can watch [Sathya Gunasekaran's](https://twitter.com/_gsathya) talk at React India here: + + + +## We recommend everyone use the React Compiler linter today {/*we-recommend-everyone-use-the-react-compiler-linter-today*/} + +React Compiler’s ESLint plugin helps developers proactively identify and correct [Rules of React](/reference/rules) violations. **We strongly recommend everyone use the linter today**. The linter does not require that you have the compiler installed, so you can use it independently, even if you are not ready to try out the compiler. + +To install the linter only: + + +npm install -D eslint-plugin-react-compiler@beta + + +Or, if you're using Yarn: + + +yarn add -D eslint-plugin-react-compiler@beta + + +After installation you can enable the linter by [adding it to your ESLint config](/learn/react-compiler#installing-eslint-plugin-react-compiler). Using the linter helps identify Rules of React breakages, making it easier to adopt the compiler when it's fully released. + +## Backwards Compatibility {/*backwards-compatibility*/} + +React Compiler produces code that depends on runtime APIs added in React 19, but we've since added support for the compiler to also work with React 17 and 18. If you are not on React 19 yet, in the Beta release you can now try out React Compiler by specifying a minimum `target` in your compiler config, and adding `react-compiler-runtime` as a dependency. [You can find docs on this here](/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Using React Compiler in libraries {/*using-react-compiler-in-libraries*/} + +Our initial release was focused on identifying major issues with using the compiler in applications. We've gotten great feedback and have substantially improved the compiler since then. We're now ready for broad feedback from the community, and for library authors to try out the compiler to improve performance and the developer experience of maintaining your library. + +React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. + +Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum `target` and add `react-compiler-runtime` as a direct dependency. The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. + +[You can find more docs on this here.](/learn/react-compiler#using-the-compiler-on-libraries) + +## Opening up React Compiler Working Group to everyone {/*opening-up-react-compiler-working-group-to-everyone*/} + +We previously announced the invite-only [React Compiler Working Group](https://github.com/reactwg/react-compiler) at React Conf to provide feedback, ask questions, and collaborate on the compiler's experimental release. + +From today, together with the Beta release of React Compiler, we are opening up Working Group membership to everyone. The goal of the React Compiler Working Group is to prepare the ecosystem for a smooth, gradual adoption of React Compiler by existing applications and libraries. Please continue to file bug reports in the [React repo](https://github.com/facebook/react), but please leave feedback, ask questions, or share ideas in the [Working Group discussion forum](https://github.com/reactwg/react-compiler/discussions). + +The core team will also use the discussions repo to share our research findings. As the Stable Release gets closer, any important information will also be posted on this forum. + +## React Compiler at Meta {/*react-compiler-at-meta*/} + +At [React Conf](/blog/2024/05/22/react-conf-2024-recap), we shared that our rollout of the compiler on Quest Store and Instagram were successful. Since then, we've deployed React Compiler across several more major web apps at Meta, including [Facebook](https://www.facebook.com) and [Threads](https://www.threads.net). That means if you've used any of these apps recently, you may have had your experience powered by the compiler. We were able to onboard these apps onto the compiler with few code changes required, in a monorepo with more than 100,000 React components. + +We've seen notable performance improvements across all of these apps. As we've rolled out, we're continuing to see results on the order of [the wins we shared previously at ReactConf](https://youtu.be/lyEKhv8-3n0?t=3223). These apps have already been heavily hand tuned and optimized by Meta engineers and React experts over the years, so even improvements on the order of a few percent are a huge win for us. + +We also expected developer productivity wins from React Compiler. To measure this, we collaborated with our data science partners at Meta[^2] to conduct a thorough statistical analysis of the impact of manual memoization on productivity. Before rolling out the compiler at Meta, we discovered that only about 8% of React pull requests used manual memoization and that these pull requests took 31-46% longer to author[^3]. This confirmed our intuition that manual memoization introduces cognitive overhead, and we anticipate that React Compiler will lead to more efficient code authoring and review. Notably, React Compiler also ensures that *all* code is memoized by default, not just the (in our case) 8% where developers explicitly apply memoization. + +## Roadmap to Stable {/*roadmap-to-stable*/} + +*This is not a final roadmap, and is subject to change.* + +We intend to ship a Release Candidate of the compiler in the near future following the Beta release, when the majority of apps and libraries that follow the Rules of React have been proven to work well with the compiler. After a period of final feedback from the community, we plan on a Stable Release for the compiler. The Stable Release will mark the beginning of a new foundation for React, and all apps and libraries will be strongly recommended to use the compiler and ESLint plugin. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from early adopters. +* ✅ Public Beta: Available today, for feedback from the wider community. +* 🚧 Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* 🚧 General Availability: After final feedback period from the community. + +These releases also include the compiler's ESLint plugin, which surfaces diagnostics statically analyzed by the compiler. We plan to combine the existing eslint-plugin-react-hooks plugin with the compiler's ESLint plugin, so only one plugin needs to be installed. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Upgrading to each new release of the compiler is aimed to be straightforward, and each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +Throughout this process, we also plan to prototype an IDE extension for React. It is still very early in research, so we expect to be able to share more of our findings with you in a future React Labs blog post. + +--- + +Thanks to [Sathya Gunasekaran](https://twitter.com/_gsathya), [Joe Savona](https://twitter.com/en_JS), [Ricky Hanlon](https://twitter.com/rickhanlonii), [Alex Taylor](https://github.com/alexmckenley), [Jason Bonta](https://twitter.com/someextent), and [Eli White](https://twitter.com/Eli_White) for reviewing and editing this post. + +--- + +[^1]: Thanks [@nikeee](https://github.com/facebook/react/pulls?q=is%3Apr+author%3Anikeee), [@henryqdineen](https://github.com/facebook/react/pulls?q=is%3Apr+author%3Ahenryqdineen), [@TrickyPi](https://github.com/facebook/react/pulls?q=is%3Apr+author%3ATrickyPi), and several others for their contributions to the compiler. + +[^2]: Thanks [Vaishali Garg](https://www.linkedin.com/in/vaishaligarg09) for leading this study on React Compiler at Meta, and for reviewing this post. + +[^3]: After controlling on author tenure, diff length/complexity, and other potential confounding factors. \ No newline at end of file diff --git a/src/content/blog/2024/12/05/react-19.md b/src/content/blog/2024/12/05/react-19.md new file mode 100644 index 000000000..62a6ce464 --- /dev/null +++ b/src/content/blog/2024/12/05/react-19.md @@ -0,0 +1,810 @@ +--- +title: "React v19" +author: The React Team +date: 2024/12/05 +description: React 19 is now available on npm! In this post, we'll give an overview of the new features in React 19, and how you can adopt them. +--- + +December 05, 2024 by [The React Team](/community/team) + +--- + + +### React 19 is now stable! {/*react-19-is-now-stable*/} + +Additions since this post was originally shared with the React 19 RC in April: + +- **Pre-warming for suspended trees**: see [Improvements to Suspense](/blog/2024/04/25/react-19-upgrade-guide#improvements-to-suspense). +- **React DOM static APIs**: see [New React DOM Static APIs](#new-react-dom-static-apis). + +_The date for this post has been updated to reflect the stable release date._ + + + + + +React v19 is now available on npm! + + + +In our [React 19 Upgrade Guide](/blog/2024/04/25/react-19-upgrade-guide), we shared step-by-step instructions for upgrading your app to React 19. In this post, we'll give an overview of the new features in React 19, and how you can adopt them. + +- [What's new in React 19](#whats-new-in-react-19) +- [Improvements in React 19](#improvements-in-react-19) +- [How to upgrade](#how-to-upgrade) + +For a list of breaking changes, see the [Upgrade Guide](/blog/2024/04/25/react-19-upgrade-guide). + +--- + +## What's new in React 19 {/*whats-new-in-react-19*/} + +### Actions {/*actions*/} + +A common use case in React apps is to perform a data mutation and then update state in response. For example, when a user submits a form to change their name, you will make an API request, and then handle the response. In the past, you would need to handle pending states, errors, optimistic updates, and sequential requests manually. + +For example, you could handle the pending and error state in `useState`: + +```js +// Before Actions +function UpdateName({}) { + const [name, setName] = useState(""); + const [error, setError] = useState(null); + const [isPending, setIsPending] = useState(false); + + const handleSubmit = async () => { + setIsPending(true); + const error = await updateName(name); + setIsPending(false); + if (error) { + setError(error); + return; + } + redirect("/path"); + }; + + return ( +
    + setName(event.target.value)} /> + + {error &&

    {error}

    } +
    + ); +} +``` + +In React 19, we're adding support for using async functions in transitions to handle pending states, errors, forms, and optimistic updates automatically. + +For example, you can use `useTransition` to handle the pending state for you: + +```js +// Using pending state from Actions +function UpdateName({}) { + const [name, setName] = useState(""); + const [error, setError] = useState(null); + const [isPending, startTransition] = useTransition(); + + const handleSubmit = () => { + startTransition(async () => { + const error = await updateName(name); + if (error) { + setError(error); + return; + } + redirect("/path"); + }) + }; + + return ( +
    + setName(event.target.value)} /> + + {error &&

    {error}

    } +
    + ); +} +``` + +The async transition will immediately set the `isPending` state to true, make the async request(s), and switch `isPending` to false after any transitions. This allows you to keep the current UI responsive and interactive while the data is changing. + + + +#### By convention, functions that use async transitions are called "Actions". {/*by-convention-functions-that-use-async-transitions-are-called-actions*/} + +Actions automatically manage submitting data for you: + +- **Pending state**: Actions provide a pending state that starts at the beginning of a request and automatically resets when the final state update is committed. +- **Optimistic updates**: Actions support the new [`useOptimistic`](#new-hook-optimistic-updates) hook so you can show users instant feedback while the requests are submitting. +- **Error handling**: Actions provide error handling so you can display Error Boundaries when a request fails, and revert optimistic updates to their original value automatically. +- **Forms**: `
    ` elements now support passing functions to the `action` and `formAction` props. Passing functions to the `action` props use Actions by default and reset the form automatically after submission. + + + +Building on top of Actions, React 19 introduces [`useOptimistic`](#new-hook-optimistic-updates) to manage optimistic updates, and a new hook [`React.useActionState`](#new-hook-useactionstate) to handle common cases for Actions. In `react-dom` we're adding [`` Actions](#form-actions) to manage forms automatically and [`useFormStatus`](#new-hook-useformstatus) to support the common cases for Actions in forms. + +In React 19, the above example can be simplified to: + +```js +// Using Actions and useActionState +function ChangeName({ name, setName }) { + const [error, submitAction, isPending] = useActionState( + async (previousState, formData) => { + const error = await updateName(formData.get("name")); + if (error) { + return error; + } + redirect("/path"); + return null; + }, + null, + ); + + return ( + + + + {error &&

    {error}

    } +
    + ); +} +``` + +In the next section, we'll break down each of the new Action features in React 19. + +### New hook: `useActionState` {/*new-hook-useactionstate*/} + +To make the common cases easier for Actions, we've added a new hook called `useActionState`: + +```js +const [error, submitAction, isPending] = useActionState( + async (previousState, newName) => { + const error = await updateName(newName); + if (error) { + // You can return any result of the action. + // Here, we return only the error. + return error; + } + + // handle success + return null; + }, + null, +); +``` + +`useActionState` accepts a function (the "Action"), and returns a wrapped Action to call. This works because Actions compose. When the wrapped Action is called, `useActionState` will return the last result of the Action as `data`, and the pending state of the Action as `pending`. + + + +`React.useActionState` was previously called `ReactDOM.useFormState` in the Canary releases, but we've renamed it and deprecated `useFormState`. + +See [#28491](https://github.com/facebook/react/pull/28491) for more info. + + + +For more information, see the docs for [`useActionState`](/reference/react/useActionState). + +### React DOM: `
    ` Actions {/*form-actions*/} + +Actions are also integrated with React 19's new `` features for `react-dom`. We've added support for passing functions as the `action` and `formAction` props of ``, ``, and `
    }> + + + ) +} +``` + + + +#### `use` does not support promises created in render. {/*use-does-not-support-promises-created-in-render*/} + +If you try to pass a promise created in render to `use`, React will warn: + + + + + +A component was suspended by an uncached promise. Creating promises inside a Client Component or hook is not yet supported, except via a Suspense-compatible library or framework. + + + + + +To fix, you need to pass a promise from a suspense powered library or framework that supports caching for promises. In the future we plan to ship features to make it easier to cache promises in render. + + + +You can also read context with `use`, allowing you to read Context conditionally such as after early returns: + +```js {1,11} +import {use} from 'react'; +import ThemeContext from './ThemeContext' + +function Heading({children}) { + if (children == null) { + return null; + } + + // This would not work with useContext + // because of the early return. + const theme = use(ThemeContext); + return ( +

    + {children} +

    + ); +} +``` + +The `use` API can only be called in render, similar to hooks. Unlike hooks, `use` can be called conditionally. In the future we plan to support more ways to consume resources in render with `use`. + +For more information, see the docs for [`use`](/reference/react/use). + +## New React DOM Static APIs {/*new-react-dom-static-apis*/} + +We've added two new APIs to `react-dom/static` for static site generation: +- [`prerender`](/reference/react-dom/static/prerender) +- [`prerenderToNodeStream`](/reference/react-dom/static/prerenderToNodeStream) + +These new APIs improve on `renderToString` by waiting for data to load for static HTML generation. They are designed to work with streaming environments like Node.js Streams and Web Streams. For example, in a Web Stream environment, you can prerender a React tree to static HTML with `prerender`: + +```js +import { prerender } from 'react-dom/static'; + +async function handler(request) { + const {prelude} = await prerender(, { + bootstrapScripts: ['/main.js'] + }); + return new Response(prelude, { + headers: { 'content-type': 'text/html' }, + }); +} +``` + +Prerender APIs will wait for all data to load before returning the static HTML stream. Streams can be converted to strings, or sent with a streaming response. They do not support streaming content as it loads, which is supported by the existing [React DOM server rendering APIs](/reference/react-dom/server). + +For more information, see [React DOM Static APIs](/reference/react-dom/static). + +## React Server Components {/*react-server-components*/} + +### Server Components {/*server-components*/} + +Server Components are a new option that allows rendering components ahead of time, before bundling, in an environment separate from your client application or SSR server. This separate environment is the "server" in React Server Components. Server Components can run once at build time on your CI server, or they can be run for each request using a web server. + +React 19 includes all of the React Server Components features included from the Canary channel. This means libraries that ship with Server Components can now target React 19 as a peer dependency with a `react-server` [export condition](https://github.com/reactjs/rfcs/blob/main/text/0227-server-module-conventions.md#react-server-conditional-exports) for use in frameworks that support the [Full-stack React Architecture](/learn/start-a-new-react-project#which-features-make-up-the-react-teams-full-stack-architecture-vision). + + + + +#### How do I build support for Server Components? {/*how-do-i-build-support-for-server-components*/} + +While React Server Components in React 19 are stable and will not break between minor versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. + +To support React Server Components as a bundler or framework, we recommend pinning to a specific React version, or using the Canary release. We will continue working with bundlers and frameworks to stabilize the APIs used to implement React Server Components in the future. + + + + +For more, see the docs for [React Server Components](/reference/rsc/server-components). + +### Server Actions {/*server-actions*/} + +Server Actions allow Client Components to call async functions executed on the server. + +When a Server Action is defined with the `"use server"` directive, your framework will automatically create a reference to the server function, and pass that reference to the Client Component. When that function is called on the client, React will send a request to the server to execute the function, and return the result. + + + +#### There is no directive for Server Components. {/*there-is-no-directive-for-server-components*/} + +A common misunderstanding is that Server Components are denoted by `"use server"`, but there is no directive for Server Components. The `"use server"` directive is used for Server Actions. + +For more info, see the docs for [Directives](/reference/rsc/directives). + + + +Server Actions can be created in Server Components and passed as props to Client Components, or they can be imported and used in Client Components. + +For more, see the docs for [React Server Actions](/reference/rsc/server-actions). + +## Improvements in React 19 {/*improvements-in-react-19*/} + +### `ref` as a prop {/*ref-as-a-prop*/} + +Starting in React 19, you can now access `ref` as a prop for function components: + +```js [[1, 1, "ref"], [1, 2, "ref", 45], [1, 6, "ref", 14]] +function MyInput({placeholder, ref}) { + return +} + +//... + +``` + +New function components will no longer need `forwardRef`, and we will be publishing a codemod to automatically update your components to use the new `ref` prop. In future versions we will deprecate and remove `forwardRef`. + + + +`refs` passed to classes are not passed as props since they reference the component instance. + + + +### Diffs for hydration errors {/*diffs-for-hydration-errors*/} + +We also improved error reporting for hydration errors in `react-dom`. For example, instead of logging multiple errors in DEV without any information about the mismatch: + + + + + +Warning: Text content did not match. Server: "Server" Client: "Client" +{' '}at span +{' '}at App + + + + + +Warning: An error occurred during hydration. The server HTML was replaced with client content in \. + + + + + +Warning: Text content did not match. Server: "Server" Client: "Client" +{' '}at span +{' '}at App + + + + + +Warning: An error occurred during hydration. The server HTML was replaced with client content in \. + + + + + +Uncaught Error: Text content does not match server-rendered HTML. +{' '}at checkForUnmatchedText +{' '}... + + + + + +We now log a single message with a diff of the mismatch: + + + + + + +Uncaught Error: Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if an SSR-ed Client Component used:{'\n'} +\- A server/client branch `if (typeof window !== 'undefined')`. +\- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called. +\- Date formatting in a user's locale which doesn't match the server. +\- External changing data without sending a snapshot of it along with the HTML. +\- Invalid HTML tag nesting.{'\n'} +It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.{'\n'} +https://react.dev/link/hydration-mismatch {'\n'} +{' '}\ +{' '}\ +{'+ '}Client +{'- '}Server{'\n'} +{' '}at throwOnHydrationMismatch +{' '}... + + + + + +### `` as a provider {/*context-as-a-provider*/} + +In React 19, you can render `` as a provider instead of ``: + + +```js {5,7} +const ThemeContext = createContext(''); + +function App({children}) { + return ( + + {children} + + ); +} +``` + +New Context providers can use `` and we will be publishing a codemod to convert existing providers. In future versions we will deprecate ``. + +### Cleanup functions for refs {/*cleanup-functions-for-refs*/} + +We now support returning a cleanup function from `ref` callbacks: + +```js {7-9} + { + // ref created + + // NEW: return a cleanup function to reset + // the ref when element is removed from DOM. + return () => { + // ref cleanup + }; + }} +/> +``` + +When the component unmounts, React will call the cleanup function returned from the `ref` callback. This works for DOM refs, refs to class components, and `useImperativeHandle`. + + + +Previously, React would call `ref` functions with `null` when unmounting the component. If your `ref` returns a cleanup function, React will now skip this step. + +In future versions, we will deprecate calling refs with `null` when unmounting components. + + + +Due to the introduction of ref cleanup functions, returning anything else from a `ref` callback will now be rejected by TypeScript. The fix is usually to stop using implicit returns, for example: + +```diff [[1, 1, "("], [1, 1, ")"], [2, 2, "{", 15], [2, 2, "}", 1]] +-
    (instance = current)} /> ++
    {instance = current}} /> +``` + +The original code returned the instance of the `HTMLDivElement` and TypeScript wouldn't know if this was _supposed_ to be a cleanup function or if you didn't want to return a cleanup function. + +You can codemod this pattern with [`no-implicit-ref-callback-return`](https://github.com/eps1lon/types-react-codemod/#no-implicit-ref-callback-return). + +### `useDeferredValue` initial value {/*use-deferred-value-initial-value*/} + +We've added an `initialValue` option to `useDeferredValue`: + +```js [[1, 1, "deferredValue"], [1, 4, "deferredValue"], [2, 4, "''"]] +function Search({deferredValue}) { + // On initial render the value is ''. + // Then a re-render is scheduled with the deferredValue. + const value = useDeferredValue(deferredValue, ''); + + return ( + + ); +} +```` + +When initialValue is provided, `useDeferredValue` will return it as `value` for the initial render of the component, and schedules a re-render in the background with the deferredValue returned. + +For more, see [`useDeferredValue`](/reference/react/useDeferredValue). + +### Support for Document Metadata {/*support-for-metadata-tags*/} + +In HTML, document metadata tags like ``, `<link>`, and `<meta>` are reserved for placement in the `<head>` section of the document. In React, the component that decides what metadata is appropriate for the app may be very far from the place where you render the `<head>` or React does not render the `<head>` at all. In the past, these elements would need to be inserted manually in an effect, or by libraries like [`react-helmet`](https://github.com/nfl/react-helmet), and required careful handling when server rendering a React application. + +In React 19, we're adding support for rendering document metadata tags in components natively: + +```js {5-8} +function BlogPost({post}) { + return ( + <article> + <h1>{post.title}</h1> + <title>{post.title} + + + +

    + Eee equals em-see-squared... +

    + + ); +} +``` + +When React renders this component, it will see the `` `<link>` and `<meta>` tags, and automatically hoist them to the `<head>` section of document. By supporting these metadata tags natively, we're able to ensure they work with client-only apps, streaming SSR, and Server Components. + +<Note> + +#### You may still want a Metadata library {/*you-may-still-want-a-metadata-library*/} + +For simple use cases, rendering Document Metadata as tags may be suitable, but libraries can offer more powerful features like overriding generic metadata with specific metadata based on the current route. These features make it easier for frameworks and libraries like [`react-helmet`](https://github.com/nfl/react-helmet) to support metadata tags, rather than replace them. + +</Note> + +For more info, see the docs for [`<title>`](/reference/react-dom/components/title), [`<link>`](/reference/react-dom/components/link), and [`<meta>`](/reference/react-dom/components/meta). + +### Support for stylesheets {/*support-for-stylesheets*/} + +Stylesheets, both externally linked (`<link rel="stylesheet" href="...">`) and inline (`<style>...</style>`), require careful positioning in the DOM due to style precedence rules. Building a stylesheet capability that allows for composability within components is hard, so users often end up either loading all of their styles far from the components that may depend on them, or they use a style library which encapsulates this complexity. + +In React 19, we're addressing this complexity and providing even deeper integration into Concurrent Rendering on the Client and Streaming Rendering on the Server with built in support for stylesheets. If you tell React the `precedence` of your stylesheet it will manage the insertion order of the stylesheet in the DOM and ensure that the stylesheet (if external) is loaded before revealing content that depends on those style rules. + +```js {4,5,17} +function ComponentOne() { + return ( + <Suspense fallback="loading..."> + <link rel="stylesheet" href="foo" precedence="default" /> + <link rel="stylesheet" href="bar" precedence="high" /> + <article class="foo-class bar-class"> + {...} + </article> + </Suspense> + ) +} + +function ComponentTwo() { + return ( + <div> + <p>{...}</p> + <link rel="stylesheet" href="baz" precedence="default" /> <-- will be inserted between foo & bar + </div> + ) +} +``` + +During Server Side Rendering React will include the stylesheet in the `<head>`, which ensures that the browser will not paint until it has loaded. If the stylesheet is discovered late after we've already started streaming, React will ensure that the stylesheet is inserted into the `<head>` on the client before revealing the content of a Suspense boundary that depends on that stylesheet. + +During Client Side Rendering React will wait for newly rendered stylesheets to load before committing the render. If you render this component from multiple places within your application React will only include the stylesheet once in the document: + +```js {5} +function App() { + return <> + <ComponentOne /> + ... + <ComponentOne /> // won't lead to a duplicate stylesheet link in the DOM + </> +} +``` + +For users accustomed to loading stylesheets manually this is an opportunity to locate those stylesheets alongside the components that depend on them allowing for better local reasoning and an easier time ensuring you only load the stylesheets that you actually depend on. + +Style libraries and style integrations with bundlers can also adopt this new capability so even if you don't directly render your own stylesheets, you can still benefit as your tools are upgraded to use this feature. + +For more details, read the docs for [`<link>`](/reference/react-dom/components/link) and [`<style>`](/reference/react-dom/components/style). + +### Support for async scripts {/*support-for-async-scripts*/} + +In HTML normal scripts (`<script src="...">`) and deferred scripts (`<script defer="" src="...">`) load in document order which makes rendering these kinds of scripts deep within your component tree challenging. Async scripts (`<script async="" src="...">`) however will load in arbitrary order. + +In React 19 we've included better support for async scripts by allowing you to render them anywhere in your component tree, inside the components that actually depend on the script, without having to manage relocating and deduplicating script instances. + +```js {4,15} +function MyComponent() { + return ( + <div> + <script async={true} src="..." /> + Hello World + </div> + ) +} + +function App() { + <html> + <body> + <MyComponent> + ... + <MyComponent> // won't lead to duplicate script in the DOM + </body> + </html> +} +``` + +In all rendering environments, async scripts will be deduplicated so that React will only load and execute the script once even if it is rendered by multiple different components. + +In Server Side Rendering, async scripts will be included in the `<head>` and prioritized behind more critical resources that block paint such as stylesheets, fonts, and image preloads. + +For more details, read the docs for [`<script>`](/reference/react-dom/components/script). + +### Support for preloading resources {/*support-for-preloading-resources*/} + +During initial document load and on client side updates, telling the Browser about resources that it will likely need to load as early as possible can have a dramatic effect on page performance. + +React 19 includes a number of new APIs for loading and preloading Browser resources to make it as easy as possible to build great experiences that aren't held back by inefficient resource loading. + +```js +import { prefetchDNS, preconnect, preload, preinit } from 'react-dom' +function MyComponent() { + preinit('https://.../path/to/some/script.js', {as: 'script' }) // loads and executes this script eagerly + preload('https://.../path/to/font.woff', { as: 'font' }) // preloads this font + preload('https://.../path/to/stylesheet.css', { as: 'style' }) // preloads this stylesheet + prefetchDNS('https://...') // when you may not actually request anything from this host + preconnect('https://...') // when you will request something but aren't sure what +} +``` +```html +<!-- the above would result in the following DOM/HTML --> +<html> + <head> + <!-- links/scripts are prioritized by their utility to early loading, not call order --> + <link rel="prefetch-dns" href="https://..."> + <link rel="preconnect" href="https://..."> + <link rel="preload" as="font" href="https://.../path/to/font.woff"> + <link rel="preload" as="style" href="https://.../path/to/stylesheet.css"> + <script async="" src="https://.../path/to/some/script.js"></script> + </head> + <body> + ... + </body> +</html> +``` + +These APIs can be used to optimize initial page loads by moving discovery of additional resources like fonts out of stylesheet loading. They can also make client updates faster by prefetching a list of resources used by an anticipated navigation and then eagerly preloading those resources on click or even on hover. + +For more details see [Resource Preloading APIs](/reference/react-dom#resource-preloading-apis). + +### Compatibility with third-party scripts and extensions {/*compatibility-with-third-party-scripts-and-extensions*/} + +We've improved hydration to account for third-party scripts and browser extensions. + +When hydrating, if an element that renders on the client doesn't match the element found in the HTML from the server, React will force a client re-render to fix up the content. Previously, if an element was inserted by third-party scripts or browser extensions, it would trigger a mismatch error and client render. + +In React 19, unexpected tags in the `<head>` and `<body>` will be skipped over, avoiding the mismatch errors. If React needs to re-render the entire document due to an unrelated hydration mismatch, it will leave in place stylesheets inserted by third-party scripts and browser extensions. + +### Better error reporting {/*error-handling*/} + +We improved error handling in React 19 to remove duplication and provide options for handling caught and uncaught errors. For example, when there's an error in render caught by an Error Boundary, previously React would throw the error twice (once for the original error, then again after failing to automatically recover), and then call `console.error` with info about where the error occurred. + +This resulted in three errors for every caught error: + +<ConsoleBlockMulti> + +<ConsoleLogLine level="error"> + +Uncaught Error: hit +{' '}at Throws +{' '}at renderWithHooks +{' '}... + +</ConsoleLogLine> + +<ConsoleLogLine level="error"> + +Uncaught Error: hit<span className="ms-2 text-gray-30">{' <--'} Duplicate</span> +{' '}at Throws +{' '}at renderWithHooks +{' '}... + +</ConsoleLogLine> + +<ConsoleLogLine level="error"> + +The above error occurred in the Throws component: +{' '}at Throws +{' '}at ErrorBoundary +{' '}at App{'\n'} +React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary. + +</ConsoleLogLine> + +</ConsoleBlockMulti> + +In React 19, we log a single error with all the error information included: + +<ConsoleBlockMulti> + +<ConsoleLogLine level="error"> + +Error: hit +{' '}at Throws +{' '}at renderWithHooks +{' '}...{'\n'} +The above error occurred in the Throws component: +{' '}at Throws +{' '}at ErrorBoundary +{' '}at App{'\n'} +React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary. +{' '}at ErrorBoundary +{' '}at App + +</ConsoleLogLine> + +</ConsoleBlockMulti> + +Additionally, we've added two new root options to complement `onRecoverableError`: + +- `onCaughtError`: called when React catches an error in an Error Boundary. +- `onUncaughtError`: called when an error is thrown and not caught by an Error Boundary. +- `onRecoverableError`: called when an error is thrown and automatically recovered. + +For more info and examples, see the docs for [`createRoot`](/reference/react-dom/client/createRoot) and [`hydrateRoot`](/reference/react-dom/client/hydrateRoot). + +### Support for Custom Elements {/*support-for-custom-elements*/} + +React 19 adds full support for custom elements and passes all tests on [Custom Elements Everywhere](https://custom-elements-everywhere.com/). + +In past versions, using Custom Elements in React has been difficult because React treated unrecognized props as attributes rather than properties. In React 19, we've added support for properties that works on the client and during SSR with the following strategy: + +- **Server Side Rendering**: props passed to a custom element will render as attributes if their type is a primitive value like `string`, `number`, or the value is `true`. Props with non-primitive types like `object`, `symbol`, `function`, or value `false` will be omitted. +- **Client Side Rendering**: props that match a property on the Custom Element instance will be assigned as properties, otherwise they will be assigned as attributes. + +Thanks to [Joey Arhar](https://github.com/josepharhar) for driving the design and implementation of Custom Element support in React. + + +#### How to upgrade {/*how-to-upgrade*/} +See the [React 19 Upgrade Guide](/blog/2024/04/25/react-19-upgrade-guide) for step-by-step instructions and a full list of breaking and notable changes. + +_Note: this post was originally published 04/25/2024 and has been updated to 12/05/2024 with the stable release._ diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 409f33701..cc50b83c0 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -10,6 +10,30 @@ This blog is the official source for the updates from the React team. Anything i <div className="sm:-mx-5 flex flex-col gap-5 mt-12"> +<BlogCard title="React v19 " date="December 5, 2024" url="/blog/2024/12/05/react-19"> + +In the React 19 Upgrade Guide, we shared step-by-step instructions for upgrading your app to React 19. In this post, we'll give an overview of the new features in React 19, and how you can adopt them ... + +</BlogCard> + +<BlogCard title="React Compiler Beta Release" date="October 21, 2024" url="/blog/2024/10/21/react-compiler-beta-release"> + +We announced an experimental release of React Compiler at React Conf 2024. We've made a lot of progress since then, and in this post we want to share what's next for React Compiler ... + +</BlogCard> + +<BlogCard title="React Conf 2024 Recap" date="May 22, 2024" url="/blog/2024/05/22/react-conf-2024-recap"> + +Last week we hosted React Conf 2024, a two-day conference in Henderson, Nevada where 700+ attendees gathered in-person to discuss the latest in UI engineering. This was our first in-person conference since 2019, and we were thrilled to be able to bring the community together again ... + +</BlogCard> + +<BlogCard title="React 19 Upgrade Guide" date="April 25, 2024" url="/blog/2024/04/25/react-19-upgrade-guide"> + +The improvements added to React 19 require some breaking changes, but we've worked to make the upgrade as smooth as possible, and we don't expect the changes to impact most apps. In this post, we will guide you through the steps for upgrading libraries to React 19 ... + +</BlogCard> + <BlogCard title="React Labs: What We've Been Working On – February 2024" date="February 15, 2024" url="/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024"> In React Labs posts, we write about projects in active research and development. Since our last update, we've made significant progress on React Compiler, new features, and React 19, and we'd like to share what we learned. diff --git a/src/content/community/acknowledgements.md b/src/content/community/acknowledgements.md index c87a92979..760076d83 100644 --- a/src/content/community/acknowledgements.md +++ b/src/content/community/acknowledgements.md @@ -4,7 +4,7 @@ title: Acknowledgements <Intro> -React was originally created by [Jordan Walke.](https://github.com/jordwalke) Today, React has a [dedicated full-time team working on it](/community/team), as well as over a thousand [open source contributors.](https://github.com/facebook/react/blob/main/AUTHORS) +React was originally created by [Jordan Walke.](https://github.com/jordwalke) Today, React has a [dedicated full-time team working on it](/community/team), as well as over a thousand [open source contributors.](https://github.com/facebook/react/graphs/contributors) </Intro> @@ -16,6 +16,7 @@ We'd like to recognize a few people who have made significant contributions to R * [Andreas Svensson](https://github.com/syranide) * [Alex Krolick](https://github.com/alexkrolick) * [Alexey Pyltsyn](https://github.com/lex111) +* [Andrey Lunyov](https://github.com/alunyov) * [Brandon Dail](https://github.com/aweary) * [Brian Vaughn](https://github.com/bvaughn) * [Caleb Meredith](https://github.com/calebmer) @@ -58,7 +59,7 @@ We'd like to recognize a few people who have made significant contributions to R This list is not exhaustive. -We'd like to give special thanks to [Tom Occhino](https://github.com/tomocchino) and [Adam Wolff](https://github.com/wolffiex) for their guidance and support over the years. We are also thankful to all the volunteers who [translated React into other languages.](https://translations.reactjs.org/) +We'd like to give special thanks to [Tom Occhino](https://github.com/tomocchino) and [Adam Wolff](https://github.com/wolffiex) for their guidance and support over the years. We are also thankful to all the volunteers who [translated React into other languages.](https://translations.react.dev/) ## Additional Thanks {/*additional-thanks*/} diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md index a28d60848..85ffe9831 100644 --- a/src/content/community/conferences.md +++ b/src/content/community/conferences.md @@ -10,88 +10,148 @@ Do you know of a local React.js conference? Add it here! (Please keep the list c ## Upcoming Conferences {/*upcoming-conferences*/} -### React Paris 2024 {/*react-paris-2024*/} -March 22, 2024. In-person in Paris, France + Remote (hybrid) +### React Day Berlin 2024 {/*react-day-berlin-2024*/} +December 13 & 16, 2024. In-person in Berlin, Germany + remote (hybrid event) -[Website](https://react.paris/) - [Twitter](https://twitter.com/BeJS_) - [LinkedIn](https://www.linkedin.com/events/7150816372074192900/comments/) +[Website](https://reactday.berlin/) - [Twitter](https://x.com/reactdayberlin) -### Epic Web Conf 2024 {/*epic-web-2024*/} -April 10 - 11, 2024. In-person in Park City, UT, USA +### App.js Conf 2025 {/*appjs-conf-2025*/} +May 28 - 30, 2025. In-person in Kraków, Poland + remote -[Website](https://www.epicweb.dev/conf) - [YouTube](https://www.youtube.com/@EpicWebDev) +[Website](https://appjs.co) - [Twitter](https://twitter.com/appjsconf) -### React Miami 2024 {/*react-miami-2024*/} -April 19 - 20, 2024. In-person in Miami, FL, USA +### React Summit 2025 {/*react-summit-2025*/} +June 13 - 17, 2025. In-person in Amsterdam, Netherlands + remote (hybrid event) -[Website](https://reactmiami.com/) - [Twitter](https://twitter.com/ReactMiamiConf) +[Website](https://reactsummit.com/) - [Twitter](https://x.com/reactsummit) -### React Connection 2024 {/*react-connection-2024*/} -April 22, 2024. In-person in Paris, France +### React Universe Conf 2025 {/*react-universe-conf-2025*/} +September 2-4, 2025. Wrocław, Poland. -[Website](https://reactconnection.io/) - [Twitter](https://twitter.com/ReactConn) +[Website](https://www.reactuniverseconf.com/) - [Twitter](https://twitter.com/react_native_eu) - [LinkedIn](https://www.linkedin.com/events/reactuniverseconf7163919537074118657/) -### React Native Connection 2024 {/*react-native-connection-2024*/} -April 23, 2024. In-person in Paris, France +## Past Conferences {/*past-conferences*/} -[Website](https://reactnativeconnection.io/) - [Twitter](https://twitter.com/ReactNativeConn) +### React Africa 2024 {/*react-africa-2024*/} +November 29, 2024. In-person in Casablanca, Morocco (hybrid event) -### React Conf 2024 {/*react-conf-2024*/} -May 15 - 16, 2024. In-person in Henderson, NV, USA + remote +[Website](https://react-africa.com/) - [Twitter](https://x.com/BeJS_) -[Website](https://conf.react.dev) - [Twitter](https://twitter.com/reactjs) +### React Summit US 2024 {/*react-summit-us-2024*/} +November 19 & 22, 2024. In-person in New York, USA + online (hybrid event) -### App.js Conf 2024 {/*appjs-conf-2024*/} -May 22 - 24, 2024. In-person in Kraków, Poland + remote +[Website](https://reactsummit.us/) - [Twitter](https://twitter.com/reactsummit) - [Videos](https://portal.gitnation.org/) -[Website](https://appjs.co) - [Twitter](https://twitter.com/appjsconf) +### React Native London Conf 2024 {/*react-native-london-2024*/} +November 14 & 15, 2024. In-person in London, UK + +[Website](https://reactnativelondon.co.uk/) - [Twitter](https://x.com/RNLConf) + +### React Advanced London 2024 {/*react-advanced-london-2024*/} +October 25 & 28, 2024. In-person in London, UK + online (hybrid event) + +[Website](https://reactadvanced.com/) - [Twitter](https://x.com/reactadvanced) + +### reactjsday 2024 {/*reactjsday-2024*/} +October 25, 2024. In-person in Verona, Italy + online (hybrid event) + +[Website](https://2024.reactjsday.it/) - [Twitter](https://x.com/reactjsday) - [Facebook](https://www.facebook.com/GrUSP/) - [YouTube](https://www.youtube.com/c/grusp) + +### React Brussels 2024 {/*react-brussels-2024*/} +October 18, 2024. In-person in Brussels, Belgium (hybrid event) + +[Website](https://www.react.brussels/) - [Twitter](https://x.com/BrusselsReact) + +### React India 2024 {/*react-india-2024*/} +October 17 - 19, 2024. In-person in Goa, India (hybrid event) + Oct 15 2024 - remote day + +[Website](https://www.reactindia.io) - [Twitter](https://twitter.com/react_india) - [Facebook](https://www.facebook.com/ReactJSIndia) - [Youtube](https://www.youtube.com/channel/UCaFbHCBkPvVv1bWs_jwYt3w) + +### RenderCon Kenya 2024 {/*rendercon-kenya-2024*/} +October 04 - 05, 2024. Nairobi, Kenya + +[Website](https://rendercon.org/) - [Twitter](https://twitter.com/renderconke) - [LinkedIn](https://www.linkedin.com/company/renderconke/) - [YouTube](https://www.youtube.com/channel/UC0bCcG8gHUL4njDOpQGcMIA) + +### React Alicante 2024 {/*react-alicante-2024*/} +September 19-21, 2024. Alicante, Spain. + +[Website](https://reactalicante.es/) - [Twitter](https://twitter.com/ReactAlicante) - [YouTube](https://www.youtube.com/channel/UCaSdUaITU1Cz6PvC97A7e0w) + +### React Universe Conf 2024 {/*react-universe-conf-2024*/} +September 5-6, 2024. Wrocław, Poland. + +[Website](https://www.reactuniverseconf.com/) - [Twitter](https://twitter.com/react_native_eu) - [LinkedIn](https://www.linkedin.com/events/reactuniverseconf7163919537074118657/) + + +### React Rally 2024 🐙 {/*react-rally-2024*/} +August 12-13, 2024. Park City, UT, USA + +[Website](https://reactrally.com) - [Twitter](https://twitter.com/ReactRally) - [YouTube](https://www.youtube.com/channel/UCXBhQ05nu3L1abBUGeQ0ahw) + +### The Geek Conf 2024 {/*the-geek-conf-2024*/} +July 25, 2024. In-person in Berlin, Germany + remote (hybrid event) + +[Website](https://thegeekconf.com) - [Twitter](https://twitter.com/thegeekconf) + +### Chain React 2024 {/*chain-react-2024*/} +July 17-19, 2024. In-person in Portland, OR, USA + +[Website](https://chainreactconf.com) - [Twitter](https://twitter.com/ChainReactConf) + +### React Nexus 2024 {/*react-nexus-2024*/} +July 04 & 05, 2024. Bangalore, India (In-person event) + +[Website](https://reactnexus.com/) - [Twitter](https://twitter.com/ReactNexus) - [Linkedin](https://www.linkedin.com/company/react-nexus) - [YouTube](https://www.youtube.com/reactify_in) ### React Summit 2024 {/*react-summit-2024*/} June 14 & 18, 2024. In-person in Amsterdam, Netherlands + remote (hybrid event) [Website](https://reactsummit.com/) - [Twitter](https://twitter.com/reactsummit) - [Videos](https://portal.gitnation.org/) -### Render(ATL) 2024 🍑 {/*renderatl-2024-*/} -June 12 - June 14, 2024. 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 Norway 2024 {/*react-norway-2024*/} June 14, 2024. In-person at Farris Bad Hotel in Larvik, Norway and online (hybrid event). [Website](https://reactnorway.com/) - [Twitter](https://twitter.com/ReactNorway) -### React Nexus 2024 {/*react-nexus-2024*/} -July 04 & 05, 2024. Bangalore, India (In-person event) +### Render(ATL) 2024 🍑 {/*renderatl-2024-*/} +June 12 - June 14, 2024. Atlanta, GA, USA -[Website](https://reactnexus.com/) - [Twitter](https://twitter.com/ReactNexus) - [Linkedin](https://www.linkedin.com/company/react-nexus) - [YouTube](https://www.youtube.com/reactify_in) +[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 2024 {/*chain-react-2024*/} -July 17-19, 2024. In-person in Portland, OR, USA +### Frontend Nation 2024 {/*frontend-nation-2024*/} +June 4 - 7, 2024. Online -[Website](https://chainreactconf.com) - [Twitter](https://twitter.com/ChainReactConf) +[Website](https://frontendnation.com/) - [Twitter](https://twitter.com/frontendnation) -### The Geek Conf 2024 {/*the-geek-conf-2024*/} -July 25, 2024. In-person in Berlin, Germany + remote (hybrid event) +### App.js Conf 2024 {/*appjs-conf-2024*/} +May 22 - 24, 2024. In-person in Kraków, Poland + remote -[Website](https://thegeekconf.com) - [Twitter](https://twitter.com/thegeekconf) +[Website](https://appjs.co) - [Twitter](https://twitter.com/appjsconf) -### React Universe Conf 2024 {/*react-universe-conf-2024*/} -September 5-6, 2024. Wrocław, Poland. +### React Conf 2024 {/*react-conf-2024*/} +May 15 - 16, 2024. In-person in Henderson, NV, USA + remote -[Website](https://www.reactuniverseconf.com/) - [Twitter](https://twitter.com/react_native_eu) - [LinkedIn](https://www.linkedin.com/events/reactuniverseconf7163919537074118657/) +[Website](https://conf.react.dev) - [Twitter](https://twitter.com/reactjs) -### React Alicante 2024 {/*react-alicante-2024*/} -September 19-21, 2024. Alicante, Spain. +### React Native Connection 2024 {/*react-native-connection-2024*/} +April 23, 2024. In-person in Paris, France -[Website](https://reactalicante.es/) - [Twitter](https://twitter.com/ReactAlicante) - [YouTube](https://www.youtube.com/channel/UCaSdUaITU1Cz6PvC97A7e0w) +[Website](https://reactnativeconnection.io/) - [Twitter](https://twitter.com/ReactNativeConn) +### React Miami 2024 {/*react-miami-2024*/} +April 19 - 20, 2024. In-person in Miami, FL, USA -### React India 2024 {/*react-india-2024*/} -October 17 - 19, 2024. In-person in Goa, India (hybrid event) + Oct 15 2024 - remote day +[Website](https://reactmiami.com/) - [Twitter](https://twitter.com/ReactMiamiConf) -[Website](https://www.reactindia.io) - [Twitter](https://twitter.com/react_india) - [Facebook](https://www.facebook.com/ReactJSIndia) - [Youtube](https://www.youtube.com/channel/UCaFbHCBkPvVv1bWs_jwYt3w) +### Epic Web Conf 2024 {/*epic-web-2024*/} +April 10 - 11, 2024. In-person in Park City, UT, USA -## Past Conferences {/*past-conferences*/} +[Website](https://www.epicweb.dev/conf) - [YouTube](https://www.youtube.com/@EpicWebDev) + +### React Paris 2024 {/*react-paris-2024*/} +March 22, 2024. In-person in Paris, France + Remote (hybrid) + +[Website](https://react.paris/) - [Twitter](https://twitter.com/BeJS_) - [LinkedIn](https://www.linkedin.com/events/7150816372074192900/comments/) - [Videos](https://www.youtube.com/playlist?list=PL53Z0yyYnpWhUzgvr2Nys3kZBBLcY0TA7) ### React Day Berlin 2023 {/*react-day-berlin-2023*/} December 8 & 12, 2023. In-person in Berlin, Germany + remote first interactivity (hybrid event) diff --git a/src/content/community/docs-contributors.md b/src/content/community/docs-contributors.md index cbdbf7d7f..0f9d002d6 100644 --- a/src/content/community/docs-contributors.md +++ b/src/content/community/docs-contributors.md @@ -4,7 +4,7 @@ title: Docs Contributors <Intro> -React documentation is written and maintained by the [React team](/community/team) and [external contributors.](https://github.com/reactjs/reactjs.org/graphs/contributors) On this page, we'd like to thank a few people who've made significant contributions to this site. +React documentation is written and maintained by the [React team](/community/team) and [external contributors.](https://github.com/reactjs/react.dev/graphs/contributors) On this page, we'd like to thank a few people who've made significant contributions to this site. </Intro> diff --git a/src/content/community/meetups.md b/src/content/community/meetups.md index a12a5349c..14097aa4d 100644 --- a/src/content/community/meetups.md +++ b/src/content/community/meetups.md @@ -30,15 +30,8 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Belo Horizonte](https://www.meetup.com/reactbh/) * [Curitiba](https://www.meetup.com/pt-br/ReactJS-CWB/) * [Florianópolis](https://www.meetup.com/pt-br/ReactJS-Floripa/) -* [Goiânia](https://www.meetup.com/pt-br/React-Goiania/) * [Joinville](https://www.meetup.com/pt-BR/React-Joinville/) -* [Juiz de Fora](https://www.meetup.com/pt-br/React-Juiz-de-Fora/) -* [Maringá](https://www.meetup.com/pt-BR/React-Maringa/) -* [Porto Alegre](https://www.meetup.com/pt-BR/React-Porto-Alegre/) -* [Rio de Janeiro](https://www.meetup.com/pt-BR/React-Rio-de-Janeiro/) -* [Salvador](https://www.meetup.com/pt-BR/ReactSSA) * [São Paulo](https://www.meetup.com/pt-BR/ReactJS-SP/) -* [Vila Velha](https://www.meetup.com/pt-BR/React-ES/) ## Bolivia {/*bolivia*/} * [Bolivia](https://www.meetup.com/ReactBolivia/) @@ -51,24 +44,13 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Saskatoon, SK](https://www.meetup.com/saskatoon-react-meetup/) * [Toronto, ON](https://www.meetup.com/Toronto-React-Native/events/) -## Chile {/*chile*/} -* [Santiago](https://www.meetup.com/es-ES/react-santiago/) - -## China {/*china*/} -* [Beijing](https://www.meetup.com/Beijing-ReactJS-Meetup/) - ## Colombia {/*colombia*/} -* [Bogotá](https://www.meetup.com/meetup-group-iHIeHykY/) * [Medellin](https://www.meetup.com/React-Medellin/) -* [Cali](https://www.meetup.com/reactcali/) ## Denmark {/*denmark*/} * [Aalborg](https://www.meetup.com/Aalborg-React-React-Native-Meetup/) * [Aarhus](https://www.meetup.com/Aarhus-ReactJS-Meetup/) -## Egypt {/*egypt*/} -* [Cairo](https://www.meetup.com/react-cairo/) - ## England (UK) {/*england-uk*/} * [Manchester](https://www.meetup.com/Manchester-React-User-Group/) * [React.JS Girls London](https://www.meetup.com/ReactJS-Girls-London/) @@ -76,7 +58,6 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [React Native London](https://guild.host/RNLDN) ## France {/*france*/} -* [Nantes](https://www.meetup.com/React-Nantes/) * [Lille](https://www.meetup.com/ReactBeerLille/) * [Paris](https://www.meetup.com/ReactJS-Paris/) @@ -93,14 +74,11 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Athens](https://www.meetup.com/React-To-React-Athens-MeetUp/) * [Thessaloniki](https://www.meetup.com/Thessaloniki-ReactJS-Meetup/) -## Hungary {/*hungary*/} -* [Budapest](https://www.meetup.com/React-Budapest/) - ## India {/*india*/} * [Ahmedabad](https://www.meetup.com/react-ahmedabad/) * [Bangalore (React)](https://www.meetup.com/ReactJS-Bangalore/) * [Bangalore (React Native)](https://www.meetup.com/React-Native-Bangalore-Meetup) -* [Chennai](https://www.meetup.com/React-Chennai/) +* [Chennai](https://www.linkedin.com/company/chennaireact) * [Delhi NCR](https://www.meetup.com/React-Delhi-NCR/) * [Mumbai](https://reactmumbai.dev) * [Pune](https://www.meetup.com/ReactJS-and-Friends/) @@ -117,6 +95,9 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet ## Italy {/*italy*/} * [Milan](https://www.meetup.com/React-JS-Milano/) +## Japan {/*japan*/} +* [Osaka](https://react-osaka.connpass.com/) + ## Kenya {/*kenya*/} * [Nairobi - Reactdevske](https://kommunity.com/reactjs-developer-community-kenya-reactdevske) @@ -138,12 +119,6 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Karachi](https://www.facebook.com/groups/902678696597634/) * [Lahore](https://www.facebook.com/groups/ReactjsLahore/) -## Panama {/*panama*/} -* [Panama](https://www.meetup.com/React-Panama/) - -## Peru {/*peru*/} -* [Lima](https://www.meetup.com/ReactJS-Peru/) - ## Philippines {/*philippines*/} * [Manila](https://www.meetup.com/reactjs-developers-manila/) * [Manila - ReactJS PH](https://www.meetup.com/ReactJS-Philippines/) @@ -160,7 +135,6 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet ## Spain {/*spain*/} * [Barcelona](https://www.meetup.com/ReactJS-Barcelona/) -* [Canarias](https://www.meetup.com/React-Canarias/) ## Sweden {/*sweden*/} * [Goteborg](https://www.meetup.com/ReactJS-Goteborg/) @@ -176,7 +150,6 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Kyiv](https://www.meetup.com/Kyiv-ReactJS-Meetup) ## US {/*us*/} -* [Ann Arbor, MI - ReactJS](https://www.meetup.com/AnnArbor-jsx/) * [Atlanta, GA - ReactJS](https://www.meetup.com/React-ATL/) * [Austin, TX - ReactJS](https://www.meetup.com/ReactJS-Austin-Meetup/) * [Boston, MA - ReactJS](https://www.meetup.com/ReactJS-Boston/) @@ -187,7 +160,6 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Cleveland, OH - ReactJS](https://www.meetup.com/Cleveland-React/) * [Columbus, OH - ReactJS](https://www.meetup.com/ReactJS-Columbus-meetup/) * [Dallas, TX - ReactJS](https://www.meetup.com/ReactDallas/) -* [Dallas, TX - [Remote] React JS](https://www.meetup.com/React-JS-Group/) * [Detroit, MI - Detroit React User Group](https://www.meetup.com/Detroit-React-User-Group/) * [Indianapolis, IN - React.Indy](https://www.meetup.com/React-Indy) * [Irvine, CA - ReactJS](https://www.meetup.com/ReactJS-OC/) @@ -197,27 +169,19 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Los Angeles, CA - ReactJS](https://www.meetup.com/socal-react/) * [Los Angeles, CA - React Native](https://www.meetup.com/React-Native-Los-Angeles/) * [Miami, FL - ReactJS](https://www.meetup.com/React-Miami/) -* [Nashville, TN - ReactJS](https://www.meetup.com/NashReact-Meetup/) * [New York, NY - ReactJS](https://www.meetup.com/NYC-Javascript-React-Group/) * [New York, NY - React Ladies](https://www.meetup.com/React-Ladies/) * [New York, NY - React Native](https://www.meetup.com/React-Native-NYC/) * [New York, NY - useReactNYC](https://www.meetup.com/useReactNYC/) * [New York, NY - React.NYC](https://guild.host/react-nyc) -* [Omaha, NE - ReactJS/React Native](https://www.meetup.com/omaha-react-meetup-group/) * [Palo Alto, CA - React Native](https://www.meetup.com/React-Native-Silicon-Valley/) -* [Philadelphia, PA - ReactJS](https://www.meetup.com/Reactadelphia/) * [Phoenix, AZ - ReactJS](https://www.meetup.com/ReactJS-Phoenix/) -* [Pittsburgh, PA - ReactJS/React Native](https://www.meetup.com/ReactPgh/) -* [Portland, OR - ReactJS](https://www.meetup.com/Portland-ReactJS/) * [Provo, UT - ReactJS](https://www.meetup.com/ReactJS-Utah/) -* [Sacramento, CA - ReactJS](https://www.meetup.com/Sacramento-ReactJS-Meetup/) * [San Diego, CA - San Diego JS](https://www.meetup.com/sandiegojs/) * [San Francisco - Real World React](https://www.meetup.com/Real-World-React) * [San Francisco - ReactJS](https://www.meetup.com/ReactJS-San-Francisco/) * [San Francisco, CA - React Native](https://www.meetup.com/React-Native-San-Francisco/) -* [San Ramon, CA - TriValley Coders](https://www.meetup.com/trivalleycoders/) * [Santa Monica, CA - ReactJS](https://www.meetup.com/Los-Angeles-ReactJS-User-Group/) -* [Seattle, WA - React Native](https://www.meetup.com/Seattle-React-Native-Meetup/) * [Seattle, WA - ReactJS](https://www.meetup.com/seattle-react-js/) * [Tampa, FL - ReactJS](https://www.meetup.com/ReactJS-Tampa-Bay/) * [Tucson, AZ - ReactJS](https://www.meetup.com/Tucson-ReactJS-Meetup/) diff --git a/src/content/community/team.md b/src/content/community/team.md index 9ef95d64a..94f31f09f 100644 --- a/src/content/community/team.md +++ b/src/content/community/team.md @@ -18,11 +18,7 @@ Current members of the React team are listed in alphabetical order below. Andrew got started with web development by making sites with WordPress, and eventually tricked himself into doing JavaScript. His favorite pastime is karaoke. Andrew is either a Disney villain or a Disney princess, depending on the day. </TeamMember> -<TeamMember name="Andrey Lunyov" permalink="andrey-lunyov" photo="/images/team/andrey-lunyov.jpg" github="alunyov" twitter="alunyov" threads="alunyov" title="Engineer at Meta"> - Andrey started his career as a designer and then gradually transitioned into web development. After joining the React Data team at Meta he worked on adding an incremental JavaScript compiler to Relay, and then later on, worked on removing the same compiler from Relay. Outside of work, Andrey likes to play music and engage in various sports. -</TeamMember> - -<TeamMember name="Dan Abramov" permalink="dan-abramov" photo="/images/team/gaearon.jpg" github="gaearon" twitter="dan_abramov" title="Independent Engineer"> +<TeamMember name="Dan Abramov" permalink="dan-abramov" photo="/images/team/gaearon.jpg" github="gaearon" bsky="danabra.mov" title="Independent Engineer"> Dan got into programming after he accidentally discovered Visual Basic inside Microsoft PowerPoint. He has found his true calling in turning [Sebastian](#sebastian-markbåge)'s tweets into long-form blog posts. Dan occasionally wins at Fortnite by hiding in a bush until the game ends. </TeamMember> @@ -30,24 +26,28 @@ Current members of the React team are listed in alphabetical order below. Eli got into programming after he got suspended from middle school for hacking. He has been working on React and React Native since 2017. He enjoys eating treats, especially ice cream and apple pie. You can find Eli trying quirky activities like parkour, indoor skydiving, and aerial silks. </TeamMember> +<TeamMember name="Jack Pope" permalink="jack-pope" photo="/images/team/jack-pope.jpg" github="jackpope" personal="jackpope.me" title="Engineer at Meta"> + Shortly after being introduced to AutoHotkey, Jack had written scripts to automate everything he could think of. When reaching limitations there, he dove headfirst into web app development and hasn't looked back. Most recently, Jack worked on the web platform at Instagram before moving to React. His favorite programming language is JSX. +</TeamMember> + <TeamMember name="Jason Bonta" permalink="jason-bonta" photo="/images/team/jasonbonta.jpg" threads="someextent" title="Engineering Manager at Meta"> - Jason likes having large volumes of Amazon packages delivered to the office so that he can build forts. Despite literally walling himself off from his team at times and not understanding how for-of loops work, we appreciate him for the unique qualities he brings to his work. + Jason abandoned embedded C for a career in front-end engineering and never looked back. Armed with esoteric CSS knowledge and a passion for beautiful UI, Jason joined Facebook in 2010, where he now feels privileged to have seen JavaScript development come of age. Though he may not understand how `for...of` loops work, he loves getting to work with brilliant people on projects that enable amazing UX. </TeamMember> <TeamMember name="Joe Savona" permalink="joe-savona" photo="/images/team/joe.jpg" github="josephsavona" twitter="en_JS" threads="joesavona" title="Engineer at Meta"> Joe was planning to major in math and philosophy but got into computer science after writing physics simulations in Matlab. Prior to React, he worked on Relay, RSocket.js, and the Skip programming language. While he’s not building some sort of reactive system he enjoys running, studying Japanese, and spending time with his family. </TeamMember> -<TeamMember name="Josh Story" permalink="josh-story" photo="/images/team/josh.jpg" github="gnoff" twitter="joshcstory" title="Engineer at Vercel"> +<TeamMember name="Josh Story" permalink="josh-story" photo="/images/team/josh.jpg" github="gnoff" bsky="storyhb.com" title="Engineer at Vercel"> Josh majored in Mathematics and discovered programming while in college. His first professional developer job was to program insurance rate calculations in Microsoft Excel, the paragon of Reactive Programming which must be why he now works on React. In between that time Josh has been an IC, Manager, and Executive at a few startups. outside of work he likes to push his limits with cooking. </TeamMember> -<TeamMember name="Lauren Tan" permalink="lauren-tan" photo="/images/team/lauren.jpg" github="poteto" twitter="potetotes" threads="potetotes" personal="no.lol" title="Engineer at Meta"> - Lauren’s programming career peaked when she first discovered the `<marquee>` tag. She’s been chasing that high ever since. When she’s not adding bugs into React, she enjoys dropping cheeky memes in chat, and playing all too many video games with her partner, and her dog Zelda. +<TeamMember name="Lauren Tan" permalink="lauren-tan" photo="/images/team/lauren.jpg" github="poteto" twitter="potetotes" threads="potetotes" bsky="no.lol" title="Engineer at Meta"> + Lauren's programming career peaked when she first discovered the `<marquee>` tag. She’s been chasing that high ever since. She studied Finance instead of CS in college, so she learned to code using Excel. Lauren enjoys dropping cheeky memes in chat, playing video games with her partner, learning Korean, and petting her dog Zelda. </TeamMember> <TeamMember name="Luna Wei" permalink="luna-wei" photo="/images/team/luna-wei.jpg" github="lunaleaps" twitter="lunaleaps" threads="lunaleaps" title="Engineer at Meta"> - Luna first learnt the fundamentals of python at the age of 6 from her father. Since then, she has been unstoppable. Luna aspires to be a gen z, and the road to success is paved with environmental advocacy, urban gardening and lots of quality time with her Voo-Doo’d (as pictured). + Luna first learnt the fundamentals of python at the age of 6 from her father. Since then, she has been unstoppable. Luna aspires to be a gen z, and the road to success is paved with environmental advocacy, urban gardening and lots of quality time with her Voo-Doo’d (as pictured). </TeamMember> <TeamMember name="Matt Carroll" permalink="matt-carroll" photo="/images/team/matt-carroll.png" github="mattcarrollcode" twitter="mattcarrollcode" threads="mattcarrollcode" title="Developer Advocate at Meta"> @@ -62,10 +62,14 @@ Current members of the React team are listed in alphabetical order below. Noah’s interest in UI programming sparked during his education in music technology at NYU. At Meta, he's worked on internal tools, browsers, web performance, and is currently focused on React. Outside of work, Noah can be found tinkering with synthesizers or spending time with his cat. </TeamMember> -<TeamMember name="Rick Hanlon" permalink="rick-hanlon" photo="/images/team/rickhanlonii.jpg" github="rickhanlonii" twitter="rickhanlonii" threads="rickhanlonii" personal="rickhanlon.codes" title="Engineer at Meta"> +<TeamMember name="Rick Hanlon" permalink="rick-hanlon" photo="/images/team/rickhanlonii.jpg" github="rickhanlonii" twitter="rickhanlonii" threads="rickhanlonii" bsky="ricky.fm" title="Engineer at Meta"> Ricky majored in theoretical math and somehow found himself on the React Native team for a couple years before joining the React team. When he's not programming you can find him snowboarding, biking, climbing, golfing, or closing GitHub issues that do not match the issue template. </TeamMember> +<TeamMember name="Ruslan Lesiutin" permalink="ruslan-lesiutin" photo="/images/team/lesiutin.jpg" github="hoxyq" twitter="ruslanlesiutin" threads="lesiutin" title="Engineer at Meta"> + Ruslan's introduction to UI programming started when he was a kid by manually editing HTML templates for his custom gaming forums. Somehow, he ended up majoring in Computer Science. He enjoys music, games, and memes. Mostly memes. +</TeamMember> + <TeamMember name="Sathya Gunasekaran " permalink="sathya-gunasekaran" photo="/images/team/sathya.jpg" github="gsathya" twitter="_gsathya" threads="gsathya.03" title="Engineer at Meta"> Sathya hated the Dragon Book in school but somehow ended up working on compilers all his career. When he's not compiling React components, he's either drinking coffee or eating yet another Dosa. </TeamMember> @@ -74,7 +78,7 @@ Current members of the React team are listed in alphabetical order below. Sebastian majored in psychology. He's usually quiet. Even when he says something, it often doesn't make sense to the rest of us until a few months later. The correct way to pronounce his surname is "mark-boa-geh" but he settled for "mark-beige" out of pragmatism -- and that's how he approaches React. </TeamMember> -<TeamMember name="Sebastian Silbermann" permalink="sebastian-silbermann" photo="/images/team/sebsilbermann.jpg" github="eps1lon" twitter="sebsilbermann" threads="sebsilbermann" title="Independent Engineer"> +<TeamMember name="Sebastian Silbermann" permalink="sebastian-silbermann" photo="/images/team/sebsilbermann.jpg" github="eps1lon" twitter="sebsilbermann" threads="sebsilbermann" title="Engineer at Vercel"> Sebastian learned programming to make the browser games he played during class more enjoyable. Eventually this lead to contributing to as much open source code as possible. Outside of coding he's busy making sure people don't confuse him with the other Sebastians and Zilberman of the React community. </TeamMember> diff --git a/src/content/community/translations.md b/src/content/community/translations.md new file mode 100644 index 000000000..4c07e6a1e --- /dev/null +++ b/src/content/community/translations.md @@ -0,0 +1,35 @@ +--- +title: Translations +--- + +<Intro> + +React docs are translated by the global community into many languages all over the world. + +</Intro> + +## Source site {/*main-site*/} + +All translations are provided from the canonical source docs: + +- [English](https://react.dev/) — [Contribute](https://github.com/reactjs/react.dev/) + +## Full translations {/*full-translations*/} + +{/* If you are a language maintainer and want to add your language here, finish the "Core" translations and edit `deployedTranslations` under `src/utils`. */} + +<LanguageList progress="complete" /> + +## In-progress translations {/*in-progress-translations*/} + +For the progress of each translation, see: [Is React Translated Yet?](https://translations.react.dev/) + +<LanguageList progress="in-progress" /> + +## How to contribute {/*how-to-contribute*/} + +You can contribute to the translation efforts! + +The community conducts the translation work for the React docs on each language-specific fork of react.dev. Typical translation work involves directly translating a Markdown file and creating a pull request. Click the "contribute" link above to the GitHub repository for your language, and follow the instructions there to help with the translation effort. + +If you want to start a new translation for your language, visit: [translations.react.dev](https://github.com/reactjs/translations.react.dev) \ No newline at end of file diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index fad926c57..7aa71efd2 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -8,6 +8,8 @@ All stable builds of React go through a high level of testing and follow semanti </Intro> +For a list of previous releases, see the [Versions](/versions) page. + ## Stable releases {/*stable-releases*/} Stable React releases (also known as "Latest" release channel) follow [semantic versioning (semver)](https://semver.org/) principles. diff --git a/src/content/learn/add-react-to-an-existing-project.md b/src/content/learn/add-react-to-an-existing-project.md index 7a7eee48d..1ed893ebf 100644 --- a/src/content/learn/add-react-to-an-existing-project.md +++ b/src/content/learn/add-react-to-an-existing-project.md @@ -21,7 +21,7 @@ Załóżmy, że masz istniejącą aplikację internetową pod adresem `example.c Oto jak polecamy to skonfigurować: 1. **Zbuduj część aplikacji w Reakcie** przy użyciu jednego z [frameworków opartych na Reakcie](/learn/start-a-new-react-project). -2. **Określ `/some-app` jako *bazową ścieżkę*** w konfiguracji twojego frameworka (oto jak: [Next.js](https://nextjs.org/docs/api-reference/next.config.js/basepath), [Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/)). +2. **Określ `/some-app` jako *bazową ścieżkę*** w konfiguracji twojego frameworka (oto jak: [Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath), [Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/)). 3. **Skonfiguruj serwer lub proxy**, aby wszystkie żądania pod adresem `/some-app/` były obsługiwane przez twoją aplikację w Reakcie. diff --git a/src/content/learn/adding-interactivity.md b/src/content/learn/adding-interactivity.md index c5124abb9..b859c544f 100644 --- a/src/content/learn/adding-interactivity.md +++ b/src/content/learn/adding-interactivity.md @@ -1,30 +1,30 @@ --- -title: Adding Interactivity +title: Dodawanie interaktywności --- <Intro> -Some things on the screen update in response to user input. For example, clicking an image gallery switches the active image. In React, data that changes over time is called *state.* You can add state to any component, and update it as needed. In this chapter, you'll learn how to write components that handle interactions, update their state, and display different output over time. +Niektóre elementy na ekranie aktualizują się w odpowiedzi na interakcje użytkownika. Na przykład kliknięcie w galerię obrazów zmienia aktywny obraz. W Reakcie dane, które zmieniają się w czasie, nazywane są *stanem* (ang. _state_). Możesz dodać stan do każdego komponentu i aktualizować go w razie potrzeby. W tym rozdziale nauczysz się, jak pisać komponenty obsługujące interakcje, aktualizujące swój stan i wyświetlające różne wyniki w czasie. </Intro> <YouWillLearn isChapter={true}> -* [How to handle user-initiated events](/learn/responding-to-events) -* [How to make components "remember" information with state](/learn/state-a-components-memory) -* [How React updates the UI in two phases](/learn/render-and-commit) -* [Why state doesn't update right after you change it](/learn/state-as-a-snapshot) -* [How to queue multiple state updates](/learn/queueing-a-series-of-state-updates) -* [How to update an object in state](/learn/updating-objects-in-state) -* [How to update an array in state](/learn/updating-arrays-in-state) +* [Jak obsługiwać zdarzenia inicjowane przez użytkownika](/learn/responding-to-events) +* [Jak sprawić, aby komponenty "pamiętały" informacje za pomocą stanu](/learn/state-a-components-memory) +* [Jak React aktualizuje interfejs użytkownika w dwóch fazach](/learn/render-and-commit) +* [Dlaczego stan nie aktualizuje się od razu po jego zmianie](/learn/state-as-a-snapshot) +* [Jak kolejkować wiele aktualizacji stanu](/learn/queueing-a-series-of-state-updates) +* [Jak zaktualizować obiekt w stanie](/learn/updating-objects-in-state) +* [Jak zaktualizować tablicę w stanie](/learn/updating-arrays-in-state) </YouWillLearn> -## Responding to events {/*responding-to-events*/} +## Reagowanie na zdarzenia {/*responding-to-events*/} -React lets you add *event handlers* to your JSX. Event handlers are your own functions that will be triggered in response to user interactions like clicking, hovering, focusing on form inputs, and so on. +React pozwala na dodawanie *procedur obsługi zdarzeń* (ang. _event handlers_) do twojej składni JSX. Procedury obsługi zdarzeń to twoje własne funkcje, które zostaną wywołane w odpowiedzi na interakcje użytkownika, takie jak kliknięcia, najechanie kursorem, skupienie na elementach formularza i inne. -Built-in components like `<button>` only support built-in browser events like `onClick`. However, you can also create your own components, and give their event handler props any application-specific names that you like. +Wbudowane komponenty, takie jak `<button>`, obsługują jedynie wbudowane zdarzenia przeglądarki, takie jak `onClick`. Jednakże możesz też tworzyć własne komponenty i nadawać ich właściwościom obsługującym zdarzenia dowolne nazwy specyficzne dla twojej aplikacji. <Sandpack> @@ -32,8 +32,8 @@ Built-in components like `<button>` only support built-in browser events like `o export default function App() { return ( <Toolbar - onPlayMovie={() => alert('Playing!')} - onUploadImage={() => alert('Uploading!')} + onPlayMovie={() => alert('Odtwarzanie!')} + onUploadImage={() => alert('Wgrywanie!')} /> ); } @@ -42,10 +42,10 @@ function Toolbar({ onPlayMovie, onUploadImage }) { return ( <div> <Button onClick={onPlayMovie}> - Play Movie + Odtwórz film </Button> <Button onClick={onUploadImage}> - Upload Image + Wgraj obraz </Button> </div> ); @@ -68,22 +68,22 @@ button { margin-right: 10px; } <LearnMore path="/learn/responding-to-events"> -Read **[Responding to Events](/learn/responding-to-events)** to learn how to add event handlers. +Przeczytaj rozdział **[Reagowanie na zdarzenia](/learn/responding-to-events)**, aby dowiedzieć się, jak dodawać procedury obsługi zdarzeń. </LearnMore> -## Stan - Pamięć komponentu {/*state-a-components-memory*/} +## Stan - pamięć komponentu {/*state-a-components-memory*/} -Components often need to change what's on the screen as a result of an interaction. Typing into the form should update the input field, clicking "next" on an image carousel should change which image is displayed, clicking "buy" puts a product in the shopping cart. Components need to "remember" things: the current input value, the current image, the shopping cart. In React, this kind of component-specific memory is called *state.* +Komponenty często muszą zmieniać to, co jest wyświetlane na ekranie w wyniku interakcji. Wpisywanie w formularzu powinno aktualizować jego pole, kliknięcie "następny" w kolejce obrazów powinno zmieniać wyświetlany obraz, kliknięcie "kup" powinno umieścić produkt w koszyku. Komponenty muszą "pamiętać" różne rzeczy: bieżącą wartość pola, bieżący obraz, zawartość koszyka. W Reakcie tego rodzaju pamięć specyficzna dla komponentu nazywana jest *stanem*. -You can add state to a component with a [`useState`](/reference/react/useState) Hook. *Hooks* are special functions that let your components use React features (state is one of those features). The `useState` Hook lets you declare a state variable. It takes the initial state and returns a pair of values: the current state, and a state setter function that lets you update it. +Możesz dodać stan do komponentu za pomocą hooka [`useState`](/reference/react/useState). *Hooki* to specjalne funkcje, które pozwalają twoim komponentom korzystać z funkcjonalności Reacta (stan jest jedną z tych funkcjonalności). Hook `useState` pozwala zadeklarować zmienną stanu. Przyjmuje on stan początkowy i zwraca parę wartości: bieżący stan oraz funkcję ustawiającą stan, która pozwala na jego aktualizację. ```js const [index, setIndex] = useState(0); const [showMore, setShowMore] = useState(false); ``` -Here is how an image gallery uses and updates state on click: +Oto jak galeria obrazów wykorzystuje i aktualizuje stan po kliknięciu: <Sandpack> @@ -112,17 +112,17 @@ export default function Gallery() { return ( <> <button onClick={handleNextClick}> - Next + Następny </button> <h2> <i>{sculpture.name} </i> - by {sculpture.artist} + autorstwa {sculpture.artist} </h2> <h3> ({index + 1} of {sculptureList.length}) </h3> <button onClick={handleMoreClick}> - {showMore ? 'Hide' : 'Show'} details + {showMore ? 'Ukryj' : 'Pokaż'} detale </button> {showMore && <p>{sculpture.description}</p>} <img @@ -138,75 +138,75 @@ export default function Gallery() { export const sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', - description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', + description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.', url: 'https://i.imgur.com/Mx7dA2Y.jpg', - alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' + alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', - description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.', + description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.', url: 'https://i.imgur.com/ZF6s192m.jpg', - alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', - description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."', + description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".', url: 'https://i.imgur.com/aTtVpES.jpg', - alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.' }, { name: 'Moai', - artist: 'Unknown Artist', - description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.', + artist: 'nieznanego', + description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.', url: 'https://i.imgur.com/RCwLEoQm.jpg', - alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', - description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.', + description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.', url: 'https://i.imgur.com/Sd1AgUOm.jpg', - alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', - description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.', + description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.', url: 'https://i.imgur.com/2heNQDcm.jpg', - alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', - description: "Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.", + description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.', url: 'https://i.imgur.com/wIdGuZwm.png', - alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', - description: "Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.", + description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).', url: 'https://i.imgur.com/AlHTAdDm.jpg', - alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.' }, { - name: 'Terracotta Army', - artist: 'Unknown Artist', - description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.', + name: 'Terakotowa Armia', + artist: 'nieznanego', + description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.', url: 'https://i.imgur.com/HMFmH6m.jpg', - alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', - description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.', + description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.', url: 'https://i.imgur.com/rN7hY6om.jpg', - alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.' }, { - name: 'Aureole', + name: 'Aureola', artist: 'Ranjani Shettar', - description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a "fine synthesis of unlikely materials."', + description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.', url: 'https://i.imgur.com/okTpbHhm.jpg', - alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.' }, { name: 'Hippos', - artist: 'Taipei Zoo', - description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.', + artist: 'Ogród Zoologiczny w Taipei', + description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.', url: 'https://i.imgur.com/6o5Vuyu.jpg', - alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.' }]; ``` @@ -229,43 +229,43 @@ button { <LearnMore path="/learn/state-a-components-memory"> -Read **[Stan - Pamięć komponentu](/learn/state-a-components-memory)** to learn how to remember a value and update it on interaction. +Przeczytaj rozdział **[Stan - Pamięć komponentu](/learn/state-a-components-memory)**, aby dowiedzieć się, jak zapamiętywać wartość i aktualizować ją podczas interakcji. </LearnMore> -## Render and commit {/*render-and-commit*/} +## Renderowanie i aktualizowanie {/*render-and-commit*/} -Before your components are displayed on the 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. +Zanim twoje komponenty zostaną wyświetlone na ekranie, muszą zostać wyrenderowane przez Reacta. Zrozumienie kroków w tym procesie pomoże ci zrozumieć, jak wykonuje się twój kod i wyjaśnić jego działanie. -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: +Wyobraź sobie, że twoje komponenty to kucharze w kuchni, którzy przygotowują smaczne dania z dostępnych składników. W tej sytuacji React jest kelnerem, który przyjmuje zamówienia od klientów i przynosi im zamówione potrawy. Ten proces zgłaszania i obsługi interfejsu użytkownika składa się z trzech kroków: -1. **Triggering** a render (delivering the diner'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. **Wywołanie (ang. _triggering_)** renderowania (przekazanie zamówienia od gościa do kuchni) +2. **Renderowanie (ang. _rendering_)** komponentu (przygotowanie zamówienia w kuchni) +3. **Aktualizowanie (ang. _committing_)** drzewa DOM (umieszczenie zamówienia na stole) <IllustrationBlock sequential> - <Illustration caption="Trigger" alt="React as a server in a restaurant, fetching orders from the users and delivering them to the Component Kitchen." src="/images/docs/illustrations/i_render-and-commit1.png" /> - <Illustration caption="Render" alt="The Card Chef gives React a fresh Card component." src="/images/docs/illustrations/i_render-and-commit2.png" /> - <Illustration caption="Commit" alt="React delivers the Card to the user at their table." src="/images/docs/illustrations/i_render-and-commit3.png" /> + <Illustration caption="Wywołanie" alt="React jako kelner w restauracji, pobierający zamówienia od użytkowników i dostarczający je do Kuchni Komponentów." src="/images/docs/illustrations/i_render-and-commit1.png" /> + <Illustration caption="Renderowanie" alt="Kucharz komponentu Card przekazuje Reactowi świeży komponent Card." src="/images/docs/illustrations/i_render-and-commit2.png" /> + <Illustration caption="Aktualizowanie" alt="React dostarcza komponent Card użytkownikowi do jego stołu." src="/images/docs/illustrations/i_render-and-commit3.png" /> </IllustrationBlock> <LearnMore path="/learn/render-and-commit"> -Read **[Render and Commit](/learn/render-and-commit)** to learn the lifecycle of a UI update. +Przeczytaj rozdział **[Renderowanie i aktualizowanie](/learn/render-and-commit)**, aby dowiedzieć się o cyklu życia aktualizacji interfejsu użytkownika. </LearnMore> -## State as a snapshot {/*state-as-a-snapshot*/} +## Stan jako migawka {/*state-as-a-snapshot*/} -Unlike regular JavaScript variables, React state behaves more like a snapshot. Setting it does not change the state variable you already have, but instead triggers a re-render. This can be surprising at first! +W przeciwieństwie do zwykłych zmiennych javascriptowych, stan w Reakcie zachowuje się bardziej jak migawka. Ustawienie stanu nie zmienia już istniejącej zmiennej stanu, lecz wywołuje przerenderowanie. Może to być na początki zaskakujące! ```js console.log(count); // 0 -setCount(count + 1); // Request a re-render with 1 -console.log(count); // Still 0! +setCount(count + 1); // Żądanie ponownego renderowania z wartością 1 +console.log(count); // Nadal 0! ``` -This behavior help you avoid subtle bugs. Here is a little chat app. Try to guess what happens if you press "Send" first and *then* change the recipient to Bob. Whose name will appear in the `alert` five seconds later? +To zachowanie pomaga unikać subtelnych błędów. Oto mała aplikacja do czatu. Spróbuj zgadnąć, co się stanie, jeśli najpierw naciśniesz "Wyślij", a *potem* zmienisz odbiorcę na Boba. Czyje imię pojawi się w `alert` pięć sekund później? <Sandpack> @@ -274,12 +274,12 @@ import { useState } from 'react'; export default function Form() { const [to, setTo] = useState('Alice'); - const [message, setMessage] = useState('Hello'); + const [message, setMessage] = useState('Cześć'); function handleSubmit(e) { e.preventDefault(); setTimeout(() => { - alert(`You said ${message} to ${to}`); + alert(`Wysłano wiadomość "${message}" do użytkownika ${to}`); }, 5000); } @@ -299,7 +299,7 @@ export default function Form() { value={message} onChange={e => setMessage(e.target.value)} /> - <button type="submit">Send</button> + <button type="submit">Wyślij</button> </form> ); } @@ -314,13 +314,13 @@ label, textarea { margin-bottom: 10px; display: block; } <LearnMore path="/learn/state-as-a-snapshot"> -Read **[State as a Snapshot](/learn/state-as-a-snapshot)** to learn why state appears "fixed" and unchanging inside the event handlers. +Przeczytaj rozdział **[Stan jako migawka](/learn/state-as-a-snapshot)**, aby dowiedzieć się, dlaczego stan wydaje się być "ustalony" i niezmienny wewnątrz funkcji obsługujących zdarzenia. </LearnMore> -## Queueing a series of state updates {/*queueing-a-series-of-state-updates*/} +## Kolejkowanie serii aktualizacji stanu {/*queueing-a-series-of-state-updates*/} -This component is buggy: clicking "+3" increments the score only once. +Ten komponent zawiera błąd: kliknięcie "+3" zwiększa wynik tylko raz. <Sandpack> @@ -342,7 +342,7 @@ export default function Counter() { increment(); increment(); }}>+3</button> - <h1>Score: {score}</h1> + <h1>Wynik: {score}</h1> </> ) } @@ -354,7 +354,7 @@ button { display: inline-block; margin: 10px; font-size: 20px; } </Sandpack> -[State as a Snapshot](/learn/state-as-a-snapshot) explains why this is happening. Setting state requests a new re-render, but does not change it in the already running code. So `score` continues to be `0` right after you call `setScore(score + 1)`. +**[Stan jako migawka](/learn/state-as-a-snapshot)** wyjaśnia, dlaczego tak się dzieje. Ustawienie stanu tworzy żądanie nowego przerenderowania, ale nie zmienia tego stanu w już działającym kodzie. Dlatego `score` nadal wynosi `0` tuż po wywołaniu `setScore(score + 1)`. ```js console.log(score); // 0 @@ -366,7 +366,7 @@ setScore(score + 1); // setScore(0 + 1); console.log(score); // 0 ``` -You can fix this by passing an *updater function* when setting state. Notice how replacing `setScore(score + 1)` with `setScore(s => s + 1)` fixes the "+3" button. This lets you queue multiple state updates. +Możesz naprawić to, przekazując *funkcję aktualizującą* (ang. _updater function_) podczas ustawiania stanu. Zauważ, jak zastąpienie `setScore(score + 1)` przez `setScore(s => s + 1)` naprawia przycisk "+3". Dzięki temu możesz kolejkować wiele aktualizacji stanu. <Sandpack> @@ -388,7 +388,7 @@ export default function Counter() { increment(); increment(); }}>+3</button> - <h1>Score: {score}</h1> + <h1>Wynik: {score}</h1> </> ) } @@ -402,15 +402,15 @@ button { display: inline-block; margin: 10px; font-size: 20px; } <LearnMore path="/learn/queueing-a-series-of-state-updates"> -Read **[Queueing a Series of State Updates](/learn/queueing-a-series-of-state-updates)** to learn how to queue a sequence of state updates. +Przeczytaj rozdział **[Kolejkowanie serii aktualizacji stanu](/learn/queueing-a-series-of-state-updates)**, aby dowiedzieć się, jak kolejkować sekwencję aktualizacji stanu. </LearnMore> ## Aktualizowanie obiektów w stanie {/*updating-objects-in-state*/} -State can hold any kind of JavaScript value, including objects. But you shouldn't change objects and arrays that you hold in the React state directly. Instead, when you want to update an object and array, you need to create a new one (or make a copy of an existing one), and then update the state to use that copy. +Stan może przechowywać dowolne wartości javascriptowe, w tym obiekty. Nie powinno się jednak bezpośrednio zmieniać obiektów i tablic, które przechowuje się w stanie Reacta. Zamiast tego, gdy chcesz zaktualizować obiekt lub tablicę, musisz stworzyć nowy obiekt (lub skopiować istniejący), a następnie zaktualizować stan, aby używał tej kopii. -Usually, you will use the `...` spread syntax to copy objects and arrays that you want to change. For example, updating a nested object could look like this: +Zazwyczaj używa się składni rozproszenia (ang. _spread syntax_) `...`, aby skopiować obiekty i tablice, które chcesz zmienić. Na przykład, aktualizacja zagnieżdżonego obiektu może wyglądać tak: <Sandpack> @@ -467,28 +467,28 @@ export default function Form() { return ( <> <label> - Name: + Imię: <input value={person.name} onChange={handleNameChange} /> </label> <label> - Title: + Tytuł: <input value={person.artwork.title} onChange={handleTitleChange} /> </label> <label> - City: + Miasto: <input value={person.artwork.city} onChange={handleCityChange} /> </label> <label> - Image: + Obraz: <input value={person.artwork.image} onChange={handleImageChange} @@ -496,10 +496,10 @@ export default function Form() { </label> <p> <i>{person.artwork.title}</i> - {' by '} + {' autorstawa '} {person.name} <br /> - (located in {person.artwork.city}) + (położone w mieście {person.artwork.city}) </p> <img src={person.artwork.image} @@ -518,7 +518,7 @@ img { width: 200px; height: 200px; } </Sandpack> -If copying objects in code gets tedious, you can use a library like [Immer](https://github.com/immerjs/use-immer) to reduce repetitive code: +Jeśli kopiowanie obiektów w kodzie staje się uciążliwe, możesz użyć biblioteki takiej jak [Immer](https://github.com/immerjs/use-immer), aby zmniejszyć ilość powtarzającego się kodu: <Sandpack> @@ -562,28 +562,28 @@ export default function Form() { return ( <> <label> - Name: + Imię: <input value={person.name} onChange={handleNameChange} /> </label> <label> - Title: + Tytuł: <input value={person.artwork.title} onChange={handleTitleChange} /> </label> <label> - City: + Miasto: <input value={person.artwork.city} onChange={handleCityChange} /> </label> <label> - Image: + Obraz: <input value={person.artwork.image} onChange={handleImageChange} @@ -591,10 +591,10 @@ export default function Form() { </label> <p> <i>{person.artwork.title}</i> - {' by '} + {' autorstwa '} {person.name} <br /> - (located in {person.artwork.city}) + (położone w mieście {person.artwork.city}) </p> <img src={person.artwork.image} @@ -633,13 +633,13 @@ img { width: 200px; height: 200px; } <LearnMore path="/learn/updating-objects-in-state"> -Read **[Aktualizowanie obiektów w stanie](/learn/updating-objects-in-state)** to learn how to update objects correctly. +Przeczytaj rozdział **[Aktualizowanie obiektów w stanie](/learn/updating-objects-in-state)**, aby dowiedzieć się, jak poprawnie aktualizować obiekty. </LearnMore> ## Aktualizowanie tablic w stanie {/*updating-arrays-in-state*/} -Arrays are another type of mutable JavaScript objects you can store in state and should treat as read-only. Just like with objects, when you want to update an array stored in state, you need to create a new one (or make a copy of an existing one), and then set state to use the new array: +Tablice są kolejnym rodzajem zmiennych obiektów javascriptowych, które można przechowywać w stanie i należy je traktować jako tylko do odczytu. Podobnie jak w przypadku obiektów, gdy chcesz zaktualizować tablicę przechowywaną w stanie, musisz stworzyć nową tablicę (lub skopiować istniejącą), a następnie ustawić stan, aby używał nowej tablicy: <Sandpack> @@ -647,9 +647,9 @@ Arrays are another type of mutable JavaScript objects you can store in state and import { useState } from 'react'; const initialList = [ - { id: 0, title: 'Big Bellies', seen: false }, - { id: 1, title: 'Lunar Landscape', seen: false }, - { id: 2, title: 'Terracotta Army', seen: true }, + { id: 0, title: 'Wielkie brzuchy', seen: false }, + { id: 1, title: 'Księżycowy krajobraz', seen: false }, + { id: 2, title: 'Terakotowa armia', seen: true }, ]; export default function BucketList() { @@ -669,8 +669,8 @@ export default function BucketList() { return ( <> - <h1>Art Bucket List</h1> - <h2>My list of art to see:</h2> + <h1>Lista dzieł sztuki</h1> + <h2>Moja lista dzieł sztuki do zobaczenia:</h2> <ItemList artworks={list} onToggle={handleToggle} /> @@ -705,7 +705,7 @@ function ItemList({ artworks, onToggle }) { </Sandpack> -If copying arrays in code gets tedious, you can use a library like [Immer](https://github.com/immerjs/use-immer) to reduce repetitive code: +Jeśli kopiowanie tablic w kodzie staje się uciążliwe, możesz użyć biblioteki takiej jak [Immer](https://github.com/immerjs/use-immer), aby zmniejszyć ilość powtarzającego się kodu: <Sandpack> @@ -714,9 +714,9 @@ import { useState } from 'react'; import { useImmer } from 'use-immer'; const initialList = [ - { id: 0, title: 'Big Bellies', seen: false }, - { id: 1, title: 'Lunar Landscape', seen: false }, - { id: 2, title: 'Terracotta Army', seen: true }, + { id: 0, title: 'Wielkie brzuchy', seen: false }, + { id: 1, title: 'Księżycowy krajobraz', seen: false }, + { id: 2, title: 'Terakotowa armia', seen: true }, ]; export default function BucketList() { @@ -733,8 +733,8 @@ export default function BucketList() { return ( <> - <h1>Art Bucket List</h1> - <h2>My list of art to see:</h2> + <h1>Lista dzieł sztuki</h1> + <h2>Moja lista dzieł sztuki do zobaczenia:</h2> <ItemList artworks={list} onToggle={handleToggle} /> @@ -789,12 +789,12 @@ function ItemList({ artworks, onToggle }) { <LearnMore path="/learn/updating-arrays-in-state"> -Read **[Aktualizowanie tablic w stanie](/learn/updating-arrays-in-state)** to learn how to update arrays correctly. +Przeczytaj rozdział **[Aktualizowanie tablic w stanie](/learn/updating-arrays-in-state)**, aby dowiedzieć się, jak poprawnie aktualizować tablice. </LearnMore> -## What's next? {/*whats-next*/} +## Co dalej? {/*whats-next*/} -Head over to [Responding to Events](/learn/responding-to-events) to start reading this chapter page by page! +Przejdź do rozdziału [Reagowanie na zdarzenia](/learn/responding-to-events), aby zacząć zgłębiać ten temat strona po stronie! -Or, if you're already familiar with these topics, why not read about [Managing State](/learn/managing-state)? +Ewentualnie, jeśli już znasz te tematy, dlaczego nie przeczytać rozdziału [Zarządzanie stanem](/learn/managing-state)? diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 03fee9fbb..fe488ff0b 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -53,13 +53,13 @@ export default function PackingList() { </Sandpack> -Zauważ, że dla niektórych komponentów `Item` właściwość `isPacked` ustawiono na `true` zamiast `false`. Chcielibyśmy, żeby przy spakowanych przedmiotach, które mają ustawione `isPacked={true}`, wyświetlał się "ptaszek" (✔). +Zauważ, że dla niektórych komponentów `Item` właściwość `isPacked` ustawiono na `true` zamiast `false`. Chcielibyśmy, żeby przy spakowanych przedmiotach, które mają ustawione `isPacked={true}`, wyświetlał się "ptaszek" (✅). Możesz to zapisać za pomocą [warunku `if`/`else`](https://developer.mozilla.org/pl/docs/Web/JavaScript/Reference/Statements/if...else) w ten sposób: ```js if (isPacked) { - return <li className="item">{name} ✔</li>; + return <li className="item">{name} ✅</li>; } return <li className="item">{name}</li>; ``` @@ -71,7 +71,7 @@ Jeśli właściwość `isPacked` jest ustawiona na `true`, ten kod **zwróci odm ```js function Item({ name, isPacked }) { if (isPacked) { - return <li className="item">{name} ✔</li>; + return <li className="item">{name} ✅</li>; } return <li className="item">{name}</li>; } @@ -160,7 +160,7 @@ W praktyce, zwykle komponenty nie zwracają `null`, ponieważ może to okazać s W poprzednim przykładzie nasz kod decydował, które (jeśli którekolwiek) drzewo JSX-owe zostanie zwrócone przez komponent. Być może widzisz pewne powtórzenia w wyniku renderowania: ```js -<li className="item">{name} ✔</li> +<li className="item">{name} ✅</li> ``` jest bardzo podobne do: @@ -174,7 +174,7 @@ Oba warunkowe rozgałęzienia zwracają `<li className="item">...</li>`: ```js if (isPacked) { - return <li className="item">{name} ✔</li>; + return <li className="item">{name} ✅</li>; } return <li className="item">{name}</li>; ``` @@ -189,7 +189,7 @@ Zamiast poniższego kodu: ```js if (isPacked) { - return <li className="item">{name} ✔</li>; + return <li className="item">{name} ✅</li>; } return <li className="item">{name}</li>; ``` @@ -199,12 +199,12 @@ Możesz napisać w ten sposób: ```js return ( <li className="item"> - {isPacked ? name + ' ✔' : name} + {isPacked ? name + ' ✅' : name} </li> ); ``` -Możesz to wyrażenie przeczytać jako: *"jeśli `isPacked` ma wartość `true`, wtedy (`?`) wyrenderuj `name + ' ✔'`, w przeciwnym razie (`:`) wyrenderuj `name`."*) +Możesz to wyrażenie przeczytać jako: *"jeśli `isPacked` ma wartość `true`, wtedy (`?`) wyrenderuj `name + ' ✅'`, w przeciwnym razie (`:`) wyrenderuj `name`."*) <DeepDive> @@ -224,7 +224,7 @@ function Item({ name, isPacked }) { <li className="item"> {isPacked ? ( <del> - {name + ' ✔'} + {name + ' ✅'} </del> ) : ( name @@ -267,7 +267,7 @@ Kolejnym powszechnie stosowanym skrótem, z którym możesz się zetknąć, jest ```js return ( <li className="item"> - {name} {isPacked && '✔'} + {name} {isPacked && '✅'} </li> ); ``` @@ -282,7 +282,7 @@ Poniżej przedstawiono przykład: function Item({ name, isPacked }) { return ( <li className="item"> - {name} {isPacked && '✔'} + {name} {isPacked && '✅'} </li> ); } @@ -338,7 +338,7 @@ Użyj warunku `if`, aby przypisać ponownie wyrażenie JSX-owe do `itemContent`, ```js if (isPacked) { - itemContent = name + " ✔"; + itemContent = name + " ✅"; } ``` @@ -358,7 +358,7 @@ Ten sposób jest najbardziej rozwlekły, jednocześnie jednak najbardziej elasty function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { - itemContent = name + " ✔"; + itemContent = name + " ✅"; } return ( <li className="item"> @@ -402,7 +402,7 @@ function Item({ name, isPacked }) { if (isPacked) { itemContent = ( <del> - {name + " ✔"} + {name + " ✅"} </del> ); } @@ -465,7 +465,7 @@ Użyj operatora warunkowego (`warunek ? a : b`), aby wyświetlić ❌, jeśli `i function Item({ name, isPacked }) { return ( <li className="item"> - {name} {isPacked && '✔'} + {name} {isPacked && '✅'} </li> ); } @@ -503,7 +503,7 @@ export default function PackingList() { function Item({ name, isPacked }) { return ( <li className="item"> - {name} {isPacked ? '✔' : '❌'} + {name} {isPacked ? '✅' : '❌'} </li> ); } diff --git a/src/content/learn/describing-the-ui.md b/src/content/learn/describing-the-ui.md index 1c15674b7..52c3cb284 100644 --- a/src/content/learn/describing-the-ui.md +++ b/src/content/learn/describing-the-ui.md @@ -327,7 +327,7 @@ W tym przykładzie użyliśmy operatora `&&` do warunkowego wyrenderowania tzw. function Item({ name, isPacked }) { return ( <li className="item"> - {name} {isPacked && '✔'} + {name} {isPacked && '✅'} </li> ); } diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 440b29139..5bf6a0acc 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -37,7 +37,7 @@ export default function App() { Możesz edytować kod bezpośrednio lub otworzyć go w nowej zakładce, klikając na przycisk "Forkuj" w prawym górnym rogu. -W całej dokumentacji natkniesz się na wiele takich sandboxów. Poza samą dokumentacją, w sieci istnieje także wiele niezależnych sandboxów, które posiadają wsparcie dla Reacta, na przykład: [CodeSandbox](https://codesandbox.io/s/new), [Stackblitz](https://stackblitz.com/fork/react) czy [CodePen](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb). +W całej dokumentacji natkniesz się na wiele takich sandboxów. Poza samą dokumentacją, w sieci istnieje także wiele niezależnych sandboxów, które posiadają wsparcie dla Reacta, na przykład: [CodeSandbox](https://codesandbox.io/s/new), [Stackblitz](https://stackblitz.com/fork/react) czy [CodePen](https://codepen.io/pen?template=QWYVwWN). ### Wypróbuj Reacta lokalnie {/*try-react-locally*/} diff --git a/src/content/learn/keeping-components-pure.md b/src/content/learn/keeping-components-pure.md index 56883d6f3..31ad895a5 100644 --- a/src/content/learn/keeping-components-pure.md +++ b/src/content/learn/keeping-components-pure.md @@ -4,38 +4,38 @@ title: Czyste komponenty <Intro> -Some JavaScript functions are *pure.* Pure functions only perform a calculation and nothing more. By strictly only writing your components as pure functions, you can avoid an entire class of baffling bugs and unpredictable behavior as your codebase grows. To get these benefits, though, there are a few rules you must follow. +Niektóre funkcje javascriptowe są *czyste.* Funkcje czyste wykonują tylko obliczenia i nic więcej. Stosując się ściśle do pisania komponentów jako funkcji czystych, można uniknąć całej grupy dezorientujących błędów i nieprzewidywalnego zachowania w miarę jak kod rozwija się. Aby uzyskać te korzyści, musisz jednak przestrzegać kilku zasad. </Intro> <YouWillLearn> -* What purity is and how it helps you avoid bugs -* How to keep components pure by keeping changes out of the render phase -* How to use Strict Mode to find mistakes in your components +* Czym jest czystość i w jaki sposób pomaga uniknąć błędów +* Jak tworzyć czyste komponenty przez trzymanie zmian poza fazą renderowania +* Jak używać trybu rygorystycznego (ang. _Strict Mode_) do znajdowania błędów w komponentach </YouWillLearn> -## Purity: Components as formulas {/*purity-components-as-formulas*/} +## Czystość: Komponenty jako formuły {/*purity-components-as-formulas*/} -In computer science (and especially the world of functional programming), [a pure function](https://wikipedia.org/wiki/Pure_function) is a function with the following characteristics: +W informatyce (zwłaszcza w świecie programowania funkcyjnego), [funkcja czysta](https://wikipedia.org/wiki/Pure_function) ma następujące cechy: -* **It minds its own business.** It does not change any objects or variables that existed before it was called. -* **Same inputs, same output.** Given the same inputs, a pure function should always return the same result. +* **Dba o swoje własne sprawy.** Nie zmienia żadnych obiektów ani zmiennych, które istniały przed jej wywołaniem. +* **Takie same dane wejściowe, taki sam wynik.** Dla takich samych danych wejściowych funkcja czysta powinna zawsze zwracać ten sam wynik. -You might already be familiar with one example of pure functions: formulas in math. +Być może znasz już jeden przykład funkcji czystych: formuły matematyczne. -Consider this math formula: <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math>. +Rozważ taki wzór: <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math>. -If <Math><MathI>x</MathI> = 2</Math> then <Math><MathI>y</MathI> = 4</Math>. Always. +Jeśli <Math><MathI>x</MathI> = 2</Math>, to wtedy <Math><MathI>y</MathI> = 4</Math>. Zawsze. -If <Math><MathI>x</MathI> = 3</Math> then <Math><MathI>y</MathI> = 6</Math>. Always. +Jeśli <Math><MathI>x</MathI> = 3</Math>, to wtedy <Math><MathI>y</MathI> = 6</Math>. Zawsze. -If <Math><MathI>x</MathI> = 3</Math>, <MathI>y</MathI> won't sometimes be <Math>9</Math> or <Math>–1</Math> or <Math>2.5</Math> depending on the time of day or the state of the stock market. +Jeśli <Math><MathI>x</MathI> = 3</Math>, to <MathI>y</MathI> nie będzie czasami wynosić <Math>9</Math> albo <Math>–1</Math>, albo <Math>2.5</Math> zależnie od pory dnia czy notowań na giełdzie. -If <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math> and <Math><MathI>x</MathI> = 3</Math>, <MathI>y</MathI> will _always_ be <Math>6</Math>. +Jeśli <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math> oraz <Math><MathI>x</MathI> = 3</Math>, to <MathI>y</MathI> _zawsze_ będzie wynosić <Math>6</Math>. -If we made this into a JavaScript function, it would look like this: +Jeśli zamienilibyśmy to na funkcję javascriptową, wyglądałaby ona tak: ```js function double(number) { @@ -43,9 +43,9 @@ function double(number) { } ``` -In the above example, `double` is a **pure function.** If you pass it `3`, it will return `6`. Always. +W powyższym przykładzie `double` jest **funkcją czystą.** Jeśli przekażesz jej `3`, zawsze zwróci `6`. -React is designed around this concept. **React assumes that every component you write is a pure function.** This means that React components you write must always return the same JSX given the same inputs: +React jest zaprojektowany wokół tego konceptu. **React zakłada, że każdy komponent, który piszesz, jest funkcją czystą.** Oznacza to, że komponenty reactowe, które piszesz, zawsze muszą zwracać ten sam JSX dla tych samych danych wejściowych: <Sandpack> @@ -53,9 +53,9 @@ React is designed around this concept. **React assumes that every component you function Recipe({ drinkers }) { return ( <ol> - <li>Boil {drinkers} cups of water.</li> - <li>Add {drinkers} spoons of tea and {0.5 * drinkers} spoons of spice.</li> - <li>Add {0.5 * drinkers} cups of milk to boil and sugar to taste.</li> + <li>Zagotuj {drinkers} filiżanki wody.</li> + <li>Dodaj {drinkers} łyżki herbaty i {0.5 * drinkers} łyżkę/łyżki przypraw.</li> + <li>Dodaj {0.5 * drinkers} filiżankę/filiżanki mleka i cukier dla smaku.</li> </ol> ); } @@ -63,10 +63,10 @@ function Recipe({ drinkers }) { export default function App() { return ( <section> - <h1>Spiced Chai Recipe</h1> - <h2>For two</h2> + <h1>Przepis na Herbatę Chai</h1> + <h2>Dla dwóch osób</h2> <Recipe drinkers={2} /> - <h2>For a gathering</h2> + <h2>Dla większej grupy</h2> <Recipe drinkers={4} /> </section> ); @@ -75,31 +75,30 @@ export default function App() { </Sandpack> -When you pass `drinkers={2}` to `Recipe`, it will return JSX containing `2 cups of water`. Always. +Kiedy przekażesz `drinkers={2}` do `Recipe`, zawsze zwróci on JSX zawierający `2 filiżanki wody`. -If you pass `drinkers={4}`, it will return JSX containing `4 cups of water`. Always. +Jeśli przekażesz `drinkers={4}`, zawsze zwróci on JSX zawierający `4 filiżanki wody`. -Just like a math formula. +Dokładnie tak jak formuła matematyczna. -You could think of your components as recipes: if you follow them and don't introduce new ingredients during the cooking process, you will get the same dish every time. That "dish" is the JSX that the component serves to React to [render.](/learn/render-and-commit) +Możesz myśleć o swoich komponentach jak o przepisach kuchennych: jeśli będziesz stosować się do nich i nie wprowadzisz nowych składników podczas procesu gotowania, otrzymasz ten sam posiłek za każdym razem. To "danie" to JSX, który komponent dostarcza do Reacta na potrzeby [renderowania.](/learn/render-and-commit) -<Illustration src="/images/docs/illustrations/i_puritea-recipe.png" alt="A tea recipe for x people: take x cups of water, add x spoons of tea and 0.5x spoons of spices, and 0.5x cups of milk" /> +<Illustration src="/images/docs/illustrations/i_puritea-recipe.png" alt="Przepis na herbatę dla x osób: weź x filiżanek wody, dodaj x łyżek herbaty i 0.5x łyżek przypraw oraz 0.5x filiżanek mleka" /> -## Side Effects: (un)intended consequences {/*side-effects-unintended-consequences*/} +## Skutki uboczne: (nie)zamierzone konsekwencje {/*side-effects-unintended-consequences*/} -React's rendering process must always be pure. Components should only *return* their JSX, and not *change* any objects or variables that existed before rendering—that would make them impure! - -Here is a component that breaks this rule: +Proces renderowania w Reakcie zawsze musi być czysty. Komponenty powinny jedynie *zwracać* swój JSX i nie *zmieniać* żadnych obiektów ani zmiennych, które istniały przed renderowaniem – to sprawiałoby, że komponenty nie są czyste! +Oto komponent, który łamie tę zasadę: <Sandpack> ```js let guest = 0; function Cup() { - // Bad: changing a preexisting variable! + // Źle: zmiana istniejącej zmiennej! guest = guest + 1; - return <h2>Tea cup for guest #{guest}</h2>; + return <h2>Filiżanka herbaty dla gościa #{guest}</h2>; } export default function TeaSet() { @@ -115,17 +114,17 @@ export default function TeaSet() { </Sandpack> -This component is reading and writing a `guest` variable declared outside of it. This means that **calling this component multiple times will produce different JSX!** And what's more, if _other_ components read `guest`, they will produce different JSX, too, depending on when they were rendered! That's not predictable. +Ten komponent odczytuje i nadpisuje zmienną `guest` zadeklarowaną poza nim. Oznacza to, że **wywołanie tego komponentu wielokrotnie spowoduje wygenerowanie różnego JSX!** Co więcej, jeśli _inne_ komponenty odczytują `guest`, również wygenerują różny JSX, w zależności od momentu renderowania! To nie jest przewidywalne. -Going back to our formula <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math>, now even if <Math><MathI>x</MathI> = 2</Math>, we cannot trust that <Math><MathI>y</MathI> = 4</Math>. Our tests could fail, our users would be baffled, planes would fall out of the sky—you can see how this would lead to confusing bugs! +Wróćmy do naszej formuły <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math>. Teraz nawet jeśli <Math><MathI>x</MathI> = 2</Math>, nie możemy być pewni, że <Math><MathI>y</MathI> = 4</Math>. Nasze testy mogłyby zakończyć się niepowodzeniem, nasi użytkownicy byliby zdumieni, a samoloty mogłyby spaść z nieba – widzisz, jak mogłoby to prowadzić do niezrozumiałych błędów! -You can fix this component by [passing `guest` as a prop instead](/learn/passing-props-to-a-component): +Możesz naprawić ten komponent, [przekazując `guest` jako właściwość](/learn/passing-props-to-a-component): <Sandpack> ```js function Cup({ guest }) { - return <h2>Tea cup for guest #{guest}</h2>; + return <h2>Filiżanka herbaty dla gościa #{guest}</h2>; } export default function TeaSet() { @@ -141,37 +140,37 @@ export default function TeaSet() { </Sandpack> -Now your component is pure, as the JSX it returns only depends on the `guest` prop. +Teraz twój komponent jest czysty, ponieważ JSX, który zwraca, zależy tylko od właściwości `guest`. -In general, you should not expect your components to be rendered in any particular order. It doesn't matter if you call <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math> before or after <Math><MathI>y</MathI> = 5<MathI>x</MathI></Math>: both formulas will resolve independently of each other. In the same way, each component should only "think for itself", and not attempt to coordinate with or depend upon others during rendering. Rendering is like a school exam: each component should calculate JSX on their own! +Ogólnie, nie powinno się oczekiwać, że komponenty zostaną wyrenderowane w określonej kolejności. Nie ma znaczenia, czy zostanie wywołane <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math> przed czy po <Math><MathI>y</MathI> = 5<MathI>x</MathI></Math>: obie formuły będą rozwiązywane niezależnie od siebie. W ten sam sposób każdy komponent powinien "myśleć samodzielnie" i nie próbować koordynować się ani zależeć od innych podczas renderowania. Renderowanie przypomina egzamin szkolny: każdy komponent powinien obliczać JSX samodzielnie! <DeepDive> -#### Detecting impure calculations with StrictMode {/*detecting-impure-calculations-with-strict-mode*/} +#### Wykrywanie nieczystych obliczeń za pomocą trybu rygorystycznego {/*detecting-impure-calculations-with-strict-mode*/} -Although you might not have used them all yet, in React there are three kinds of inputs that you can read while rendering: [props](/learn/passing-props-to-a-component), [state](/learn/state-a-components-memory), and [context.](/learn/passing-data-deeply-with-context) You should always treat these inputs as read-only. +Choć być może jeszcze nie wszystkie zostały przez ciebie użyte, w Reakcie istnieją trzy rodzaje danych wejściowych, które można odczytywać podczas renderowania: [właściwości](/learn/passing-props-to-a-component), [stan](/learn/state-a-components-memory) i [kontekst.](/learn/passing-data-deeply-with-context) Zawsze powinno się traktować te dane wejściowe tylko jako do odczytu. -When you want to *change* something in response to user input, you should [set state](/learn/state-a-components-memory) instead of writing to a variable. You should never change preexisting variables or objects while your component is rendering. +Kiedy chce się *zmienić* coś w odpowiedzi na interakcję użytkownika, powinno się [ustawić stan](/learn/state-a-components-memory) zamiast zapisywać do zmiennej. Nigdy nie powinno się zmieniać istniejących zmiennych lub obiektów podczas renderowania komponentu. -React offers a "Strict Mode" in which it calls each component's function twice during development. **By calling the component functions twice, Strict Mode helps find components that break these rules.** +React oferuje "tryb rygorystyczny" (ang. _Strict Mode_), w którym, w trybie deweloperskim, wywołuje on funkcję każdego komponentu dwukrotnie. **Poprzez dwukrotne wywołanie, tryb rygorystyczny pomaga znaleźć komponenty, które łamią te zasady.** -Notice how the original example displayed "Guest #2", "Guest #4", and "Guest #6" instead of "Guest #1", "Guest #2", and "Guest #3". The original function was impure, so calling it twice broke it. But the fixed pure version works even if the function is called twice every time. **Pure functions only calculate, so calling them twice won't change anything**--just like calling `double(2)` twice doesn't change what's returned, and solving <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math> twice doesn't change what <MathI>y</MathI> is. Same inputs, same outputs. Always. +Zauważ, że oryginalny przykład wyświetlał "Gość #2", "Gość #4" i "Gość #6" zamiast "Gość #1", "Gość #2" i "Gość #3". Oryginalna funkcja była nieczysta, więc jej dwukrotne wywołanie zepsuło ją. Ale naprawiona, czysta wersja działa nawet wtedy, gdy funkcja jest wywoływana dwukrotnie za każdym razem. **Czyste funkcje tylko obliczają, więc ich dwukrotne wywołanie nic nie zmienia** — tak samo jak dwukrotne wywołanie `double(2)` nie zmienia tego, co jest zwracane, a rozwiązanie równania <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math> dwukrotnie nie zmienia wartości <MathI>y</MathI>. Te same dane wejściowe, te same dane wyjściowe. Zawsze. -Strict Mode has no effect in production, so it won't slow down the app for your users. To opt into Strict Mode, you can wrap your root component into `<React.StrictMode>`. Some frameworks do this by default. +Tryb rygorystyczny nie ma wpływu na wersję produkcyjną, więc nie spowolni aplikacji dla użytkowników. Aby wybrać tryb rygorystyczny, musisz opakować swój główny komponent w `<React.StrictMode>`. Niektóre frameworki robią to domyślnie. </DeepDive> -### Local mutation: Your component's little secret {/*local-mutation-your-components-little-secret*/} +### Lokalna mutacja: mały sekret twojego komponentu {/*local-mutation-your-components-little-secret*/} -In the above example, the problem was that the component changed a *preexisting* variable while rendering. This is often called a **"mutation"** to make it sound a bit scarier. Pure functions don't mutate variables outside of the function's scope or objects that were created before the call—that makes them impure! +W powyższym przykładzie problemem było to, że komponent zmieniał *istniejącą wcześniej* zmienną podczas renderowania. Często nazywa się to **"mutacją"**, aby brzmiało trochę bardziej przerażająco. Funkcje czyste nie mutują zmiennych i obiektów spoza ich zakresu, które zostały utworzone przed wywołaniem funkcji - co czyniłoby je nieczystymi! -However, **it's completely fine to change variables and objects that you've *just* created while rendering.** In this example, you create an `[]` array, assign it to a `cups` variable, and then `push` a dozen cups into it: +Jednak **jest całkowicie dopuszczalne zmienianie zmiennych i obiektów, które właśnie utworzono podczas renderowania.** W tym przykładzie stworzoną tablicę `[]`, przypisuje się do zmiennej `cups`, a następnie używa funkcji `push`, aby dodać do niej tuzin filiżanek: <Sandpack> ```js function Cup({ guest }) { - return <h2>Tea cup for guest #{guest}</h2>; + return <h2>Filiżanka herbaty dla gościa #{guest}</h2>; } export default function TeaGathering() { @@ -185,43 +184,43 @@ export default function TeaGathering() { </Sandpack> -If the `cups` variable or the `[]` array were created outside the `TeaGathering` function, this would be a huge problem! You would be changing a *preexisting* object by pushing items into that array. +Jeśli zmienna `cups` lub tablica `[]` zostałyby utworzone poza funkcją `TeaGathering`, byłby to ogromny problem! Zmieniałoby się *istniejący wcześniej* obiekt, dodając do niego elementy. -However, it's fine because you've created them *during the same render*, inside `TeaGathering`. No code outside of `TeaGathering` will ever know that this happened. This is called **"local mutation"**—it's like your component's little secret. +Jednakże tu jest to całkowicie w porządku, ponieważ zostały one utworzone *w trakcie tego samego renderowania*, wewnątrz funkcji `TeaGathering`. Żaden kod spoza `TeaGathering` nigdy nie będzie wiedział, że to się wydarzyło. Nazywa się to **"lokalną mutacją"** — to jak taki mały sekret twojego komponentu. -## Where you _can_ cause side effects {/*where-you-_can_-cause-side-effects*/} +## Gdzie _można_ uruchamiać efekty uboczne {/*where-you-_can_-cause-side-effects*/} -While functional programming relies heavily on purity, at some point, somewhere, _something_ has to change. That's kind of the point of programming! These changes—updating the screen, starting an animation, changing the data—are called **side effects.** They're things that happen _"on the side"_, not during rendering. +Podczas gdy programowanie funkcyjne opiera się głównie na czystości, w pewnym momencie, gdzieś, _coś_ musi się zmienić. To jest właśnie cel programowania! Zmiany te — aktualizacja ekranu, uruchomienie animacji, zmiana danych — nazywane są **efektami ubocznymi**. To rzeczy, które dzieją się _"na boku"_, a nie podczas renderowania. -In React, **side effects usually belong inside [event handlers.](/learn/responding-to-events)** Event handlers are functions that React runs when you perform some action—for example, when you click a button. Even though event handlers are defined *inside* your component, they don't run *during* rendering! **So event handlers don't need to be pure.** +W Reakcie **efekty uboczne zazwyczaj należą do [procedur obsługi zdarzeń.](/learn/responding-to-events)** Są to funkcje, które React uruchamia, gdy wykonasz jakąś akcję - na przykład gdy klikasz przycisk. Chociaż procedury obsługi zdarzeń są zdefiniowane *wewnątrz* twojego komponentu, nie uruchamiają się one *podczas* renderowania! **Dlatego nie muszą być one czyste.** -If you've exhausted all other options and can't find the right event handler for your side effect, you can still attach it to your returned JSX with a [`useEffect`](/reference/react/useEffect) call in your component. This tells React to execute it later, after rendering, when side effects are allowed. **However, this approach should be your last resort.** +Jeśli wyczerpano wszystkie inne opcje i nie można znaleźć odpowiedniej procedury obsługi zdarzeń dla twojego efektu ubocznego, nadal można dołączyć go do zwróconego JSXa za pomocą wywołania [`useEffect`](/reference/react/useEffect) w twoim komponencie. Powiadamia to Reacta, aby wykonał go później, po renderowaniu, gdy efekty uboczne są dozwolone. **Jednakże ten sposób powinien być rozwiązaniem ostatecznym.** -When possible, try to express your logic with rendering alone. You'll be surprised how far this can take you! +Kiedy to możliwe, staraj się wyrazić swoją logikę tylko za pomocą renderowania. Zdziwisz się, jak daleko możesz zajść używając tego sposobu! <DeepDive> -#### Why does React care about purity? {/*why-does-react-care-about-purity*/} +#### Dlaczego React dba o czystość? {/*why-does-react-care-about-purity*/} -Writing pure functions takes some habit and discipline. But it also unlocks marvelous opportunities: +Pisanie czystych funkcji wymaga pewnych nawyków i dyscypliny. Ale otwiera także fantastyczne możliwości: -* Your components could run in a different environment—for example, on the server! Since they return the same result for the same inputs, one component can serve many user requests. -* You can improve performance by [skipping rendering](/reference/react/memo) components whose inputs have not changed. This is safe because pure functions always return the same results, so they are safe to cache. -* If some data changes in the middle of rendering a deep component tree, React can restart rendering without wasting time to finish the outdated render. Purity makes it safe to stop calculating at any time. +* Twoje komponenty mogą działać w różnym środowisku — na przykład na serwerze! Ponieważ zwracają one ten sam wynik dla tych samych danych wejściowych, jeden komponent może obsłużyć wiele żądań użytkowników. +* Możesz poprawić wydajność, [pomijając renderowanie](/reference/react/memo) komponentów, których dane wejściowe się nie zmieniły. Jest to bezpieczne, ponieważ czyste funkcje zawsze zwracają te same wyniki, więc mogą być bezpiecznie przechowywane w pamięci podręcznej. +* Jeśli niektóre dane zmieniają się w trakcie renderowania głębokiego drzewa komponentów, React może zrestartować renderowanie bez marnowania czasu na zakończenie poprzedniego, przestarzałego renderowania. Czystość sprawia, że ​​można bezpiecznie zatrzymać obliczenia w dowolnym momencie. -Every new React feature we're building takes advantage of purity. From data fetching to animations to performance, keeping components pure unlocks the power of the React paradigm. +Każda nowa funkcjonalność Reacta, którą budujemy, opiera się na tej z czystości. Od pobierania danych, przez animacje, aż po wydajność, zachowanie komponentów w czystości uwalnia moc paradygmatu Reacta. </DeepDive> <Recap> -* A component must be pure, meaning: - * **It minds its own business.** It should not change any objects or variables that existed before rendering. - * **Same inputs, same output.** Given the same inputs, a component should always return the same JSX. -* Rendering can happen at any time, so components should not depend on each others' rendering sequence. -* You should not mutate any of the inputs that your components use for rendering. That includes props, state, and context. To update the screen, ["set" state](/learn/state-a-components-memory) instead of mutating preexisting objects. -* Strive to express your component's logic in the JSX you return. When you need to "change things", you'll usually want to do it in an event handler. As a last resort, you can `useEffect`. -* Writing pure functions takes a bit of practice, but it unlocks the power of React's paradigm. +* Komponent musi być czysty, co oznacza: + * **Dba o swoje sprawy.** Nie powinien zmieniać żadnych obiektów ani zmiennych, które istniały przed renderowaniem. + * **Takie same dane wejściowe, taki sam wynik.** Dla tych samych danych wejściowych komponent powinien zawsze zwracać ten sam JSX. +* Renderowanie może wystąpić w dowolnym momencie, dlatego komponenty nie powinny zależeć od kolejności renderowania się nawzajem. +* Nie powinno się zmieniać żadnych danych wejściowych, których używają twoje komponenty do renderowania. Obejmuje to właściwości, stan i kontekst. Aby zaktualizować widok, [ustaw stan](/learn/state-a-components-memory) zamiast modyfikować istniejące obiekty. +* Staraj się wyrażać logikę swojego komponentu przez zwracany JSX. Gdy potrzeba "coś zmienić", zazwyczaj powinno się zrobić to w obsłudze zdarzeń. W ostateczności można użyć `useEffect`. +* Pisanie czystych funkcji wymaga trochę praktyki, ale uwalnia moc paradygmatu Reacta. </Recap> @@ -229,15 +228,15 @@ Every new React feature we're building takes advantage of purity. From data fetc <Challenges> -#### Fix a broken clock {/*fix-a-broken-clock*/} +#### Napraw zepsuty zegar {/*fix-a-broken-clock*/} -This component tries to set the `<h1>`'s CSS class to `"night"` during the time from midnight to six hours in the morning, and `"day"` at all other times. However, it doesn't work. Can you fix this component? +Ten komponent próbuje ustawić klasę CSS znacznika `<h1>` na `"night"` w godzinach od północy do szóstej rano oraz na `"day"` w pozostałych godzinach. Jednakże nie działa on poprawnie. Czy możesz to naprawić? -You can verify whether your solution works by temporarily changing the computer's timezone. When the current time is between midnight and six in the morning, the clock should have inverted colors! +Możesz zweryfikować, czy twoje rozwiązanie działa, tymczasowo zmieniając strefę czasową na komputerze. Gdy obecny czas to pomiędzy północą a szóstą rano, zegar powinien mieć odwrócone kolory! <Hint> -Rendering is a *calculation*, it shouldn't try to "do" things. Can you express the same idea differently? +Renderowanie to *obliczanie*, nie powinno ono próbować "wykonywać" żadnych działań. Czy potrafisz wyrazić tę samą ideę w inny sposób? </Hint> @@ -301,7 +300,7 @@ body > * { <Solution> -You can fix this component by calculating the `className` and including it in the render output: +Ten komponent można naprawić poprzez obliczenie wartości `className` i uwzględnienie jej w wyjściu renderowania. <Sandpack> @@ -362,19 +361,19 @@ body > * { </Sandpack> -In this example, the side effect (modifying the DOM) was not necessary at all. You only needed to return JSX. +W tym przykładzie, skutek uboczny (modyfikacja drzewa DOM) w ogóle nie był konieczny. Wystarczyło zwrócić JSX. </Solution> -#### Fix a broken profile {/*fix-a-broken-profile*/} +#### Napraw uszkodzony profil {/*fix-a-broken-profile*/} -Two `Profile` components are rendered side by side with different data. Press "Collapse" on the first profile, and then "Expand" it. You'll notice that both profiles now show the same person. This is a bug. +Dwa komponenty `Profile` są renderowane obok siebie z różnymi danymi. Kliknij "Zwiń" na pierwszym profilu, a następnie "Rozwiń" go ponownie. Zauważysz, że oba profile teraz pokazują tę samą osobę. To jest błąd. -Find the cause of the bug and fix it. +Znajdź przyczynę błędu i napraw ją. <Hint> -The buggy code is in `Profile.js`. Make sure you read it all from top to bottom! +Błąd znajduje się w pliku `Profile.js`. Upewnij się, że przeczytałeś/przeczytałaś go od góry do dołu! </Hint> @@ -421,7 +420,7 @@ export default function Panel({ children }) { return ( <section className="panel"> <button onClick={() => setOpen(!open)}> - {open ? 'Collapse' : 'Expand'} + {open ? 'Zwiń' : 'Rozwiń'} </button> {open && children} </section> @@ -475,9 +474,9 @@ h1 { margin: 5px; font-size: 18px; } <Solution> -The problem is that the `Profile` component writes to a preexisting variable called `currentPerson`, and the `Header` and `Avatar` components read from it. This makes *all three of them* impure and difficult to predict. +Problemem jest to, że komponent `Profile` zapisuje do już istniejącej zmiennej o nazwie `currentPerson`, a komponenty `Header` i `Avatar` odczytują z niej. Powoduje to, że *wszystkie trzy* komponenty stają się nieczyste i trudne do przewidzenia. -To fix the bug, remove the `currentPerson` variable. Instead, pass all information from `Profile` to `Header` and `Avatar` via props. You'll need to add a `person` prop to both components and pass it all the way down. +Aby naprawić ten błąd, usuń zmienną `currentPerson`. Zamiast jej, przekaż wszystkie informacje z `Profile` do `Header` i `Avatar` za pomocą właściwości. Będziesz musieć dodać właściwość `person` do obu komponentów i przekazać je w dół. <Sandpack> @@ -571,15 +570,15 @@ h1 { margin: 5px; font-size: 18px; } </Sandpack> -Remember that React does not guarantee that component functions will execute in any particular order, so you can't communicate between them by setting variables. All communication must happen through props. +Pamiętaj, że React nie gwarantuje, że funkcje komponentów zostaną wykonane w określonej kolejności, dlatego nie możesz komunikować się między nimi poprzez ustawianie zmiennych. Wszelka komunikacja musi odbywać się za pomocą właściwości. </Solution> -#### Fix a broken story tray {/*fix-a-broken-story-tray*/} +#### Naprawa uszkodzonej palety z historiami {/*fix-a-broken-story-tray*/} -The CEO of your company is asking you to add "stories" to your online clock app, and you can't say no. You've written a `StoryTray` component that accepts a list of `stories`, followed by a "Create Story" placeholder. +Prezes twojej firmy prosi cię o dodanie "historii" do twojej aplikacji z zegarem online i nie możesz odmówić. Napisałeś/aś komponent `StoryTray`, który przyjmuje listę `stories`, a na końcu dodaje element zastępczy "Utwórz historię". -You implemented the "Create Story" placeholder by pushing one more fake story at the end of the `stories` array that you receive as a prop. But for some reason, "Create Story" appears more than once. Fix the issue. +Zaimplementowałeś/aś element zastępczy "Utwórz historię" przez dodanie "udawanej" historii na koniec tablicy `stories`, którą otrzymujesz jako właściwość. Jednakże z jakiegoś powodu "Utwórz historię" pojawia się więcej niż raz. Napraw ten problem. <Sandpack> @@ -587,7 +586,7 @@ You implemented the "Create Story" placeholder by pushing one more fake story at export default function StoryTray({ stories }) { stories.push({ id: 'create', - label: 'Create Story' + label: 'Utwórz historię' }); return ( @@ -607,8 +606,8 @@ import { useState, useEffect } from 'react'; import StoryTray from './StoryTray.js'; let initialStories = [ - {id: 0, label: "Ankit's Story" }, - {id: 1, label: "Taylor's Story" }, + {id: 0, label: "Historia Ankity" }, + {id: 1, label: "Historia Taylora" }, ]; export default function App() { @@ -675,11 +674,11 @@ li { <Solution> -Notice how whenever the clock updates, "Create Story" is added *twice*. This serves as a hint that we have a mutation during rendering--Strict Mode calls components twice to make these issues more noticeable. +Zauważ, że za każdym razem, gdy zegar się aktualizuje, "Utwórz historię" jest dodawane *dwukrotnie*. Jest to znak, że mamy mutację podczas renderowania -- tryb rygorystyczny wywołuje komponenty dwukrotnie, aby uwydatnić te problemy. -`StoryTray` function is not pure. By calling `push` on the received `stories` array (a prop!), it is mutating an object that was created *before* `StoryTray` started rendering. This makes it buggy and very difficult to predict. +Funkcja `StoryTray` nie jest czysta. Wywołanie `push` na otrzymanej tablicy `stories` (właściwość!), mutuje obiekt, który został utworzony *przed* rozpoczęciem renderowania `StoryTray`. To sprawia, że funkcja ta jest podatna na błędy i bardzo trudna do przewidzenia. -The simplest fix is to not touch the array at all, and render "Create Story" separately: +Najprostszym rozwiązaniem jest w ogóle nie modyfikować tablicy, a renderować "Utwórz historię" osobno: <Sandpack> @@ -692,7 +691,7 @@ export default function StoryTray({ stories }) { {story.label} </li> ))} - <li>Create Story</li> + <li>Utwórz historię</li> </ul> ); } @@ -703,8 +702,8 @@ import { useState, useEffect } from 'react'; import StoryTray from './StoryTray.js'; let initialStories = [ - {id: 0, label: "Ankit's Story" }, - {id: 1, label: "Taylor's Story" }, + {id: 0, label: "Historia Ankity" }, + {id: 1, label: "Historia Taylora" }, ]; export default function App() { @@ -763,19 +762,19 @@ li { </Sandpack> -Alternatively, you could create a _new_ array (by copying the existing one) before you push an item into it: +Ewentualnie, możesz utworzyć _nową_ tablicę (poprzez skopiowanie istniejącej) przed dodaniem do niej elementu: <Sandpack> ```js src/StoryTray.js active export default function StoryTray({ stories }) { - // Copy the array! + // Skopiuj tablicę! let storiesToDisplay = stories.slice(); - // Does not affect the original array: + // Nie wpływa na oryginalną tablicę: storiesToDisplay.push({ id: 'create', - label: 'Create Story' + label: 'Utwórz historię' }); return ( @@ -795,8 +794,8 @@ import { useState, useEffect } from 'react'; import StoryTray from './StoryTray.js'; let initialStories = [ - {id: 0, label: "Ankit's Story" }, - {id: 1, label: "Taylor's Story" }, + {id: 0, label: "Historia Ankity" }, + {id: 1, label: "Historia Taylora" }, ]; export default function App() { @@ -855,9 +854,9 @@ li { </Sandpack> -This keeps your mutation local and your rendering function pure. However, you still need to be careful: for example, if you tried to change any of the array's existing items, you'd have to clone those items too. +To sprawia, że twoja mutacja jest lokalna a funkcja renderowania czysta. Jednak nadal trzeba zachować ostrożność: na przykład, jeśli spróbujesz zmienić jakiekolwiek z istniejących elementów tablicy, będziesz musieć skopiować również te elementy. -It is useful to remember which operations on arrays mutate them, and which don't. For example, `push`, `pop`, `reverse`, and `sort` will mutate the original array, but `slice`, `filter`, and `map` will create a new one. +Należy pamiętać, które operacje na tablicach mutują je, a które nie. Na przykład, użycie metod `push`, `pop`, `reverse` i `sort` zmienia oryginalną tablicę, ale metody `slice`, `filter` i `map` tworzą nową tablicę. </Solution> diff --git a/src/content/learn/managing-state.md b/src/content/learn/managing-state.md index df2b85dca..8208ea68f 100644 --- a/src/content/learn/managing-state.md +++ b/src/content/learn/managing-state.md @@ -300,7 +300,7 @@ Przeczytaj rozdział pt. **[Współdzielenie stanu między komponentami](/learn/ </LearnMore> -## Utrzymywanie i resetowanie stanu {/*preserving-and-resetting-state*/} +## Zachowywanie i resetowanie stanu {/*preserving-and-resetting-state*/} Kiedy ponownie renderujesz komponent, React musi zdecydować, które części drzewa należy zostawić (i zaktualizować), a które odrzucić lub stworzyć na nowo. W większości przypadków React sam zdecyduje, co należy zrobić. Domyślnie React zachowuje części drzewa, które pokrywają się z poprzednim drzewem komponentów. @@ -496,7 +496,7 @@ textarea { <LearnMore path="/learn/preserving-and-resetting-state"> -Przeczytaj rozdział pt. **[Utrzymywanie i resetowanie stanu](/learn/preserving-and-resetting-state)**, aby nauczyć się cyklu życia stanu i jak nim zarządzać. +Przeczytaj rozdział pt. **[Zachowywanie i resetowanie stanu](/learn/preserving-and-resetting-state)**, aby nauczyć się cyklu życia stanu i jak nim zarządzać. </LearnMore> diff --git a/src/content/learn/manipulating-the-dom-with-refs.md b/src/content/learn/manipulating-the-dom-with-refs.md index 3d5cbfd1d..e366ea7cc 100644 --- a/src/content/learn/manipulating-the-dom-with-refs.md +++ b/src/content/learn/manipulating-the-dom-with-refs.md @@ -124,35 +124,35 @@ export default function CatFriends() { <> <nav> <button onClick={handleScrollToFirstCat}> - Tom + Neo </button> <button onClick={handleScrollToSecondCat}> - Maru + Millie </button> <button onClick={handleScrollToThirdCat}> - Jellylorum + Bella </button> </nav> <div> <ul> <li> <img - src="https://placekitten.com/g/200/200" - alt="Tom" + src="https://placecats.com/neo/300/200" + alt="Neo" ref={firstCatRef} /> </li> <li> <img - src="https://placekitten.com/g/300/200" - alt="Maru" + src="https://placecats.com/millie/200/200" + alt="Millie" ref={secondCatRef} /> </li> <li> <img - src="https://placekitten.com/g/250/200" - alt="Jellylorum" + src="https://placecats.com/bella/199/200" + alt="Bella" ref={thirdCatRef} /> </li> @@ -218,18 +218,19 @@ This example shows how you can use this approach to scroll to an arbitrary node <Sandpack> ```js -import { useRef } from 'react'; +import { useRef, useState } from "react"; export default function CatFriends() { const itemsRef = useRef(null); + const [catList, setCatList] = useState(setupCatList); - function scrollToId(itemId) { + function scrollToCat(cat) { const map = getMap(); - const node = map.get(itemId); + const node = map.get(cat); node.scrollIntoView({ - behavior: 'smooth', - block: 'nearest', - inline: 'center' + behavior: "smooth", + block: "nearest", + inline: "center", }); } @@ -244,34 +245,25 @@ export default function CatFriends() { return ( <> <nav> - <button onClick={() => scrollToId(0)}> - Tom - </button> - <button onClick={() => scrollToId(5)}> - Maru - </button> - <button onClick={() => scrollToId(9)}> - Jellylorum - </button> + <button onClick={() => scrollToCat(catList[0])}>Neo</button> + <button onClick={() => scrollToCat(catList[5])}>Millie</button> + <button onClick={() => scrollToCat(catList[9])}>Bella</button> </nav> <div> <ul> - {catList.map(cat => ( + {catList.map((cat) => ( <li - key={cat.id} + key={cat} ref={(node) => { const map = getMap(); - if (node) { - map.set(cat.id, node); - } else { - map.delete(cat.id); - } + map.set(cat, node); + + return () => { + map.delete(cat); + }; }} > - <img - src={cat.imageUrl} - alt={'Cat #' + cat.id} - /> + <img src={cat} /> </li> ))} </ul> @@ -280,12 +272,13 @@ export default function CatFriends() { ); } -const catList = []; -for (let i = 0; i < 10; i++) { - catList.push({ - id: i, - imageUrl: 'https://placekitten.com/250/200?image=' + i - }); +function setupCatList() { + const catList = []; + for (let i = 0; i < 10; i++) { + catList.push("https://loremflickr.com/320/240/cat?lock=" + i); + } + + return catList; } ``` @@ -325,92 +318,64 @@ In this example, `itemsRef` doesn't hold a single DOM node. Instead, it holds a key={cat.id} ref={node => { const map = getMap(); - if (node) { - // Add to the Map - map.set(cat.id, node); - } else { + // Add to the Map + map.set(cat, node); + + return () => { // Remove from the Map - map.delete(cat.id); - } + map.delete(cat); + }; }} > ``` This lets you read individual DOM nodes from the Map later. +<Note> + +When Strict Mode is enabled, ref callbacks will run twice in development. + +Read more about [how this helps find bugs](/reference/react/StrictMode#fixing-bugs-found-by-re-running-ref-callbacks-in-development) in callback refs. + +</Note> + </DeepDive> ## Accessing another component's DOM nodes {/*accessing-another-components-dom-nodes*/} -When you put a ref on a built-in component that outputs a browser element like `<input />`, React will set that ref's `current` property to the corresponding DOM node (such as the actual `<input />` in the browser). +<Pitfall> +Refs are an escape hatch. Manually manipulating _another_ component's DOM nodes can make your code fragile. +</Pitfall> -However, if you try to put a ref on **your own** component, like `<MyInput />`, by default you will get `null`. Here is an example demonstrating it. Notice how clicking the button **does not** focus the input: - -<Sandpack> +You can pass refs from parent component to child components [just like any other prop](/learn/passing-props-to-a-component). -```js +```js {3-4,9} import { useRef } from 'react'; -function MyInput(props) { - return <input {...props} />; +function MyInput({ ref }) { + return <input ref={ref} />; } -export default function MyForm() { +function MyForm() { const inputRef = useRef(null); - - function handleClick() { - inputRef.current.focus(); - } - - return ( - <> - <MyInput ref={inputRef} /> - <button onClick={handleClick}> - Focus the input - </button> - </> - ); + return <MyInput ref={inputRef} /> } ``` -</Sandpack> - -To help you notice the issue, React also prints an error to the console: - -<ConsoleBlock level="error"> - -Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? - -</ConsoleBlock> - -This happens because by default React does not let a component access the DOM nodes of other components. Not even for its own children! This is intentional. Refs are an escape hatch that should be used sparingly. Manually manipulating _another_ component's DOM nodes makes your code even more fragile. - -Instead, components that _want_ to expose their DOM nodes have to **opt in** to that behavior. A component can specify that it "forwards" its ref to one of its children. Here's how `MyInput` can use the `forwardRef` API: - -```js -const MyInput = forwardRef((props, ref) => { - return <input {...props} ref={ref} />; -}); -``` - -This is how it works: - -1. `<MyInput ref={inputRef} />` tells React to put the corresponding DOM node into `inputRef.current`. However, it's up to the `MyInput` component to opt into that--by default, it doesn't. -2. The `MyInput` component is declared using `forwardRef`. **This opts it into receiving the `inputRef` from above as the second `ref` argument** which is declared after `props`. -3. `MyInput` itself passes the `ref` it received to the `<input>` inside of it. +In the above example, a ref is created in the parent component, `MyForm`, and is passed to the child component, `MyInput`. `MyInput` then passes the ref to `<input>`. Because `<input>` is a [built-in component](/reference/react-dom/components/common) React sets the `.current` property of the ref to the `<input>` DOM element. -Now clicking the button to focus the input works: +The `inputRef` created in `MyForm` now points to the `<input>` DOM element returned by `MyInput`. A click handler created in `MyForm` can access `inputRef` and call `focus()` to set the focus on `<input>`. <Sandpack> ```js -import { forwardRef, useRef } from 'react'; +import { useRef } from 'react'; -const MyInput = forwardRef((props, ref) => { - return <input {...props} ref={ref} />; -}); +function MyInput({ ref }) { + return <input ref={ref} />; +} -export default function Form() { +export default function MyForm() { const inputRef = useRef(null); function handleClick() { @@ -430,24 +395,18 @@ export default function Form() { </Sandpack> -In design systems, it is a common pattern for low-level components like buttons, inputs, and so on, to forward their refs to their DOM nodes. On the other hand, high-level components like forms, lists, or page sections usually won't expose their DOM nodes to avoid accidental dependencies on the DOM structure. - <DeepDive> #### Exposing a subset of the API with an imperative handle {/*exposing-a-subset-of-the-api-with-an-imperative-handle*/} -In the above example, `MyInput` exposes the original DOM input element. This lets the parent component call `focus()` on it. However, this also lets the parent component do something else--for example, change its CSS styles. In uncommon cases, you may want to restrict the exposed functionality. You can do that with `useImperativeHandle`: +In the above example, the ref passed to `MyInput` is passed on to the original DOM input element. This lets the parent component call `focus()` on it. However, this also lets the parent component do something else--for example, change its CSS styles. In uncommon cases, you may want to restrict the exposed functionality. You can do that with [`useImperativeHandle`](/reference/react/useImperativeHandle): <Sandpack> ```js -import { - forwardRef, - useRef, - useImperativeHandle -} from 'react'; +import { useRef, useImperativeHandle } from "react"; -const MyInput = forwardRef((props, ref) => { +function MyInput({ ref }) { const realInputRef = useRef(null); useImperativeHandle(ref, () => ({ // Only expose focus and nothing else @@ -455,8 +414,8 @@ const MyInput = forwardRef((props, ref) => { realInputRef.current.focus(); }, })); - return <input {...props} ref={realInputRef} />; -}); + return <input ref={realInputRef} />; +}; export default function Form() { const inputRef = useRef(null); @@ -468,9 +427,7 @@ export default function Form() { return ( <> <MyInput ref={inputRef} /> - <button onClick={handleClick}> - Focus the input - </button> + <button onClick={handleClick}>Focus the input</button> </> ); } @@ -478,7 +435,7 @@ export default function Form() { </Sandpack> -Here, `realInputRef` inside `MyInput` holds the actual input DOM node. However, `useImperativeHandle` instructs React to provide your own special object as the value of a ref to the parent component. So `inputRef.current` inside the `Form` component will only have the `focus` method. In this case, the ref "handle" is not the DOM node, but the custom object you create inside `useImperativeHandle` call. +Here, `realInputRef` inside `MyInput` holds the actual input DOM node. However, [`useImperativeHandle`](/reference/react/useImperativeHandle) instructs React to provide your own special object as the value of a ref to the parent component. So `inputRef.current` inside the `Form` component will only have the `focus` method. In this case, the ref "handle" is not the DOM node, but the custom object you create inside [`useImperativeHandle`](/reference/react/useImperativeHandle) call. </DeepDive> @@ -493,7 +450,7 @@ In general, you [don't want](/learn/referencing-values-with-refs#best-practices- React sets `ref.current` during the commit. Before updating the DOM, React sets the affected `ref.current` values to `null`. After updating the DOM, React immediately sets them to the corresponding DOM nodes. -**Usually, you will access refs from event handlers.** If you want to do something with a ref, but there is no particular event to do it in, you might need an Effect. We will discuss effects on the next pages. +**Usually, you will access refs from event handlers.** If you want to do something with a ref, but there is no particular event to do it in, you might need an Effect. We will discuss Effects on the next pages. <DeepDive> @@ -590,7 +547,7 @@ export default function TodoList() { const newTodo = { id: nextId++, text: text }; flushSync(() => { setText(''); - setTodos([ ...todos, newTodo]); + setTodos([ ...todos, newTodo]); }); listRef.current.lastChild.scrollIntoView({ behavior: 'smooth', @@ -923,7 +880,7 @@ const catList = []; for (let i = 0; i < 10; i++) { catList.push({ id: i, - imageUrl: 'https://placekitten.com/250/200?image=' + i + imageUrl: 'https://loremflickr.com/250/200/cat?lock=' + i }); } @@ -1040,7 +997,7 @@ const catList = []; for (let i = 0; i < 10; i++) { catList.push({ id: i, - imageUrl: 'https://placekitten.com/250/200?image=' + i + imageUrl: 'https://loremflickr.com/250/200/cat?lock=' + i }); } diff --git a/src/content/learn/preserving-and-resetting-state.md b/src/content/learn/preserving-and-resetting-state.md index 0a884d46a..d47dcfe04 100644 --- a/src/content/learn/preserving-and-resetting-state.md +++ b/src/content/learn/preserving-and-resetting-state.md @@ -1,28 +1,28 @@ --- -title: Utrzymywanie i resetowanie stanu +title: Zachowywanie i resetowanie stanu --- <Intro> -State is isolated between components. React keeps track of which state belongs to which component based on their place in the UI tree. You can control when to preserve state and when to reset it between re-renders. +Stan jest izolowany między komponentami. React śledzi, który stan należy do którego komponentu na podstawie ich miejsca w drzewie interfejsu użytkownika. Możesz kontrolować, kiedy zachować stan, a kiedy go zresetować między renderowaniami. </Intro> <YouWillLearn> -* When React chooses to preserve or reset the state -* How to force React to reset component's state -* How keys and types affect whether the state is preserved +* Kiedy React decyduje, aby zachować lub zresetować stan +* Jak zmusić React do zresetowania stanu komponentu +* Jak klucze i typy wpływają na to, czy stan jest zachowany </YouWillLearn> -## State is tied to a position in the render tree {/*state-is-tied-to-a-position-in-the-tree*/} +## Stan jest powiązany z pozycją w drzewie renderowania {/*state-is-tied-to-a-position-in-the-tree*/} -React builds [render trees](learn/understanding-your-ui-as-a-tree#the-render-tree) for the component structure in your UI. +React buduje [drzewa renderowania](learn/understanding-your-ui-as-a-tree#the-render-tree) dla struktury komponentów w twoim interfejsie użytkownika. -When you give a component state, you might think the state "lives" inside the component. But the state is actually held inside React. React associates each piece of state it's holding with the correct component by where that component sits in the render tree. +Kiedy dodajesz stan do komponentu, możesz myśleć, że stan "żyje" wewnątrz komponentu. Jednak w rzeczywistości jest on przechowywany wewnątrz Reacta. Kojarzy on każdą część stanu, którą przechowuje, z odpowiednim komponentem na podstawie jego miejsca w drzewie renderowania. -Here, there is only one `<Counter />` JSX tag, but it's rendered at two different positions: +W poniższym przykładzie, jest tylko jeden tag `<Counter />` w składni JSX, ale jest renderowany na dwóch różnych pozycjach: <Sandpack> @@ -56,7 +56,7 @@ function Counter() { > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -86,23 +86,23 @@ label { </Sandpack> -Here's how these look as a tree: +Oto jak te komponenty wyglądają jako drzewo: <DiagramGroup> -<Diagram name="preserving_state_tree" height={248} width={395} alt="Diagram of a tree of React components. The root node is labeled 'div' and has two children. Each of the children are labeled 'Counter' and both contain a state bubble labeled 'count' with value 0."> +<Diagram name="preserving_state_tree" height={248} width={395} alt="Diagram drzewa komponentów Reacta. Węzeł główny jest oznaczony jako 'div' i ma dwóch potomków. Każdy z nich jest oznaczony jako 'Counter' i oba zawierają chmurkę stanu oznaczoną 'count' z wartością 0."> -React tree +Drzewo Reacta </Diagram> </DiagramGroup> -**These are two separate counters because each is rendered at its own position in the tree.** You don't usually have to think about these positions to use React, but it can be useful to understand how it works. +**To są dwa oddzielne liczniki, ponieważ każdy jest renderowany na swojej własnej pozycji w drzewie.** Zazwyczaj nie musisz myśleć o tych pozycjach, aby korzystać z Reacta, ale zrozumienie zasady działania może okazać się przydatne. -In React, each component on the screen has fully isolated state. For example, if you render two `Counter` components side by side, each of them will get its own, independent, `score` and `hover` states. +W Reakcie, każdy komponent na ekranie ma całkowicie izolowany stan. Na przykład, jeśli renderujesz dwa komponenty `Counter` obok siebie, każdy z nich będzie miał swoje własne, niezależne stany `score` i `hover`. -Try clicking both counters and notice they don't affect each other: +Spróbuj klikać oba liczniki i zauważ, że nie wpływają one na siebie nawzajem: <Sandpack> @@ -135,7 +135,7 @@ function Counter() { > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -160,21 +160,21 @@ function Counter() { </Sandpack> -As you can see, when one counter is updated, only the state for that component is updated: +Jak widać, gdy jeden licznik jest aktualizowany, tylko stan dla tego komponentu jest aktualizowany: <DiagramGroup> -<Diagram name="preserving_state_increment" height={248} width={441} alt="Diagram of a tree of React components. The root node is labeled 'div' and has two children. The left child is labeled 'Counter' and contains a state bubble labeled 'count' with value 0. The right child is labeled 'Counter' and contains a state bubble labeled 'count' with value 1. The state bubble of the right child is highlighted in yellow to indicate its value has updated."> +<Diagram name="preserving_state_increment" height={248} width={441} alt="Diagram drzewa komponentów Reacta. Węzeł główny jest oznaczony jako 'div' i ma dwóch potomków. Lewa gałąź jest oznaczona jako 'Counter' i zawiera chmurkę stanu oznaczoną 'count' z wartością 0. Prawa gałąź jest oznaczona jako 'Counter' i zawiera chmurkę stanu oznaczoną 'count' z wartością 1. Chmurka stanu prawej gałęzi jest podświetlona na żółto, aby wskazać, że jej wartość została zaktualizowana."> -Updating state +Aktualizacja stanu </Diagram> </DiagramGroup> -React will keep the state around for as long as you render the same component at the same position in the tree. To see this, increment both counters, then remove the second component by unchecking "Render the second counter" checkbox, and then add it back by ticking it again: +React będzie przechowywać stan tak długo, jak długo renderujesz ten sam komponent na tej samej pozycji w drzewie. Aby to zaobserwować, zwiększ oba liczniki, a następnie usuń drugi komponent, odznaczając pole wyboru "Renderuj drugi licznik", a potem dodaj go z powrotem, zaznaczając je ponownie: <Sandpack> @@ -195,7 +195,7 @@ export default function App() { setShowB(e.target.checked) }} /> - Render the second counter + Renderuj drugi licznik </label> </div> ); @@ -218,7 +218,7 @@ function Counter() { > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -248,35 +248,35 @@ label { </Sandpack> -Notice how the moment you stop rendering the second counter, its state disappears completely. That's because when React removes a component, it destroys its state. +Zauważ, że w momencie, gdy przestajesz renderować drugi licznik, jego stan znika całkowicie. Dzieje się tak, ponieważ kiedy React usuwa komponent, niszczy też jego stan. <DiagramGroup> -<Diagram name="preserving_state_remove_component" height={253} width={422} alt="Diagram of a tree of React components. The root node is labeled 'div' and has two children. The left child is labeled 'Counter' and contains a state bubble labeled 'count' with value 0. The right child is missing, and in its place is a yellow 'poof' image, highlighting the component being deleted from the tree."> +<Diagram name="preserving_state_remove_component" height={253} width={422} alt="Diagram drzewa komponentów Reacta. Węzeł główny jest oznaczony jako 'div' i ma dwóch potomków. Lewa gałąź jest oznaczona jako 'Counter' i zawiera chmurkę stanu oznaczoną 'count' z wartością 0. Prawa gałąź jest nieobecna, a na jej miejscu znajduje się żółty obrazek 'puf', podkreślający usunięcie komponentu z drzewa."> -Deleting a component +Usuwanie komponentu </Diagram> </DiagramGroup> -When you tick "Render the second counter", a second `Counter` and its state are initialized from scratch (`score = 0`) and added to the DOM. +Kiedy zaznaczasz pole wyboru "Renderuj drugi licznik", drugi komponent `Counter` i jego stan są inicjalizowane od nowa (`score = 0`) i dodawane do drzewa DOM. <DiagramGroup> -<Diagram name="preserving_state_add_component" height={258} width={500} alt="Diagram of a tree of React components. The root node is labeled 'div' and has two children. The left child is labeled 'Counter' and contains a state bubble labeled 'count' with value 0. The right child is labeled 'Counter' and contains a state bubble labeled 'count' with value 0. The entire right child node is highlighted in yellow, indicating that it was just added to the tree."> +<Diagram name="preserving_state_add_component" height={258} width={500} alt="Diagram drzewa komponentów Reacta. Węzeł główny jest oznaczony jako 'div' i ma dwóch potomków. Lewa gałąź jest oznaczona jako 'Counter' i zawiera chmurkę stanu oznaczoną 'count' z wartością 0. Prawa gałąź jest oznaczona jako 'Counter' i zawiera chmurkę stanu oznaczoną 'count' z wartością 0. Cała prawa gałąź jest podświetlona na żółto, wskazując, że została właśnie dodana do drzewa."> -Adding a component +Dodawanie komponentu </Diagram> </DiagramGroup> -**React preserves a component's state for as long as it's being rendered at its position in the UI tree.** If it gets removed, or a different component gets rendered at the same position, React discards its state. +**React zachowuje stan komponentu tak długo, jak jest on renderowany na swojej pozycji w drzewie UI.** Jeśli zostanie on usunięty lub na jego miejsce zostanie wyrenderowany inny komponent, React odrzuci jego stan. -## Same component at the same position preserves state {/*same-component-at-the-same-position-preserves-state*/} +## Ten sam komponent na tej samej pozycji zachowuje stan {/*same-component-at-the-same-position-preserves-state*/} -In this example, there are two different `<Counter />` tags: +W tym przykładzie znajdują się dwa różne tagi `<Counter />`: <Sandpack> @@ -300,7 +300,7 @@ export default function App() { setIsFancy(e.target.checked) }} /> - Use fancy styling + Użyj wyszukanego stylu </label> </div> ); @@ -326,7 +326,7 @@ function Counter({ isFancy }) { > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -361,24 +361,24 @@ label { </Sandpack> -When you tick or clear the checkbox, the counter state does not get reset. Whether `isFancy` is `true` or `false`, you always have a `<Counter />` as the first child of the `div` returned from the root `App` component: +Gdy zaznaczysz lub odznaczysz pole wyboru, stan licznika nie jest resetowany. Niezależnie od tego, czy `isFancy` jest ustawione na `true`, czy `false`, komponent `<Counter />` jest zawsze pierwszym potomkiem elementu `div` zwracanego z głównego komponentu `App` <DiagramGroup> -<Diagram name="preserving_state_same_component" height={461} width={600} alt="Diagram with two sections separated by an arrow transitioning between them. Each section contains a layout of components with a parent labeled 'App' containing a state bubble labeled isFancy. This component has one child labeled 'div', which leads to a prop bubble containing isFancy (highlighted in purple) passed down to the only child. The last child is labeled 'Counter' and contains a state bubble with label 'count' and value 3 in both diagrams. In the left section of the diagram, nothing is highlighted and the isFancy parent state value is false. In the right section of the diagram, the isFancy parent state value has changed to true and it is highlighted in yellow, and so is the props bubble below, which has also changed its isFancy value to true."> +<Diagram name="preserving_state_same_component" height={461} width={600} alt="Diagram z dwoma sekcjami oddzielonymi strzałką przechodzącą między nimi. Każda sekcja zawiera układ komponentów z rodzicem oznaczonym jako 'App', zawierającym chmurkę ze stanem o etykiecie isFancy. Ten komponent ma jednego potomka oznaczonego jako 'div', który prowadzi do chmurki z właściwością isFancy (podświetloną na fioletowo) przekazywaną do jedynego potomka. Ostatni potomek jest oznaczony jako 'Counter' i zawiera chmurkę ze stanem o etykiecie 'count' i wartości 3 w obu diagramach. W lewej sekcji diagramu nic nie jest podświetlone, a wartość stanu isFancy rodzica wynosi false. W prawej sekcji diagramu wartość stanu isFancy rodzica zmieniła się na true i jest podświetlona na żółto, podobnie jak chmurka właściwości poniżej, której wartość isFancy również zmieniła się na true."> -Updating the `App` state does not reset the `Counter` because `Counter` stays in the same position +Aktualizacja stanu `App` nie resetuje `Counter`, ponieważ `Counter` pozostaje na tej samej pozycji </Diagram> </DiagramGroup> -It's the same component at the same position, so from React's perspective, it's the same counter. +To ten sam komponent na tej samej pozycji, więc z perspektywy Reacta to jest ten sam licznik. <Pitfall> -Remember that **it's the position in the UI tree--not in the JSX markup--that matters to React!** This component has two `return` clauses with different `<Counter />` JSX tags inside and outside the `if`: +Pamiętaj, że to pozycja w drzewie UI — a nie w kodzie JSX — ma znaczenie dla Reacta! Ten komponent ma dwa wyrażenia `return` z różnymi tagami `<Counter />` wewnątrz i na zewnątrz instrukcji if: <Sandpack> @@ -399,7 +399,7 @@ export default function App() { setIsFancy(e.target.checked) }} /> - Use fancy styling + Użyj wyszukanego stylu </label> </div> ); @@ -415,7 +415,7 @@ export default function App() { setIsFancy(e.target.checked) }} /> - Use fancy styling + Użyj wyszukanego stylu </label> </div> ); @@ -441,7 +441,7 @@ function Counter({ isFancy }) { > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -476,15 +476,15 @@ label { </Sandpack> -You might expect the state to reset when you tick checkbox, but it doesn't! This is because **both of these `<Counter />` tags are rendered at the same position.** React doesn't know where you place the conditions in your function. All it "sees" is the tree you return. +Możesz oczekiwać, że stan zostanie zresetowany, gdy zaznaczysz pole wyboru, ale tak się nie stanie! Dzieje się tak, ponieważ **oba tagi `<Counter />` są renderowane na tej samej pozycji.** React nie wie, gdzie umieszczasz warunki w swojej funkcji. Wszystko, co „widzi”, to drzewo, które zwracasz. -In both cases, the `App` component returns a `<div>` with `<Counter />` as a first child. To React, these two counters have the same "address": the first child of the first child of the root. This is how React matches them up between the previous and next renders, regardless of how you structure your logic. +W obu przypadkach komponent `App` zwraca element `<div>` z komponentem `<Counter />` jako pierwszym potomkiem. Dla Reacta te dwa liczniki mają ten sam „adres”: pierwszy potomek pierwszego potomka głównego węzła. W taki sposób React łączy je między poprzednimi a kolejnymi renderowaniami, niezależnie od tego, jaką strukturę ma twoja logika. </Pitfall> -## Different components at the same position reset state {/*different-components-at-the-same-position-reset-state*/} +## Różne komponenty na tej samej pozycji resetują stan {/*different-components-at-the-same-position-reset-state*/} -In this example, ticking the checkbox will replace `<Counter>` with a `<p>`: +W tym przykładzie zaznaczenie pola wyboru zastąpi komponent `<Counter>` elementem `<p>`: <Sandpack> @@ -496,7 +496,7 @@ export default function App() { return ( <div> {isPaused ? ( - <p>See you later!</p> + <p>Do zobaczenia później!</p> ) : ( <Counter /> )} @@ -508,7 +508,7 @@ export default function App() { setIsPaused(e.target.checked) }} /> - Take a break + Zrób przerwę </label> </div> ); @@ -531,7 +531,7 @@ function Counter() { > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -561,13 +561,13 @@ label { </Sandpack> -Here, you switch between _different_ component types at the same position. Initially, the first child of the `<div>` contained a `Counter`. But when you swapped in a `p`, React removed the `Counter` from the UI tree and destroyed its state. +Tutaj przełączasz się między _różnymi_ typami komponentów na tej samej pozycji. Początkowo, pierwszy potomek `<div>` zawierał komponent `Counter`. Jednak kiedy zamieniono go na `p`, React usunął komponent `Counter` z drzewa UI i zniszczył jego stan. <DiagramGroup> -<Diagram name="preserving_state_diff_pt1" height={290} width={753} alt="Diagram with three sections, with an arrow transitioning each section in between. The first section contains a React component labeled 'div' with a single child labeled 'Counter' containing a state bubble labeled 'count' with value 3. The middle section has the same 'div' parent, but the child component has now been deleted, indicated by a yellow 'proof' image. The third section has the same 'div' parent again, now with a new child labeled 'p', highlighted in yellow."> +<Diagram name="preserving_state_diff_pt1" height={290} width={753} alt="Diagram z trzema sekcjami, z przejściami między sekcjami za pomocą strzałki. Pierwsza sekcja zawiera komponent Reacta o nazwie 'div' z jednym potomkiem oznaczonym jako 'Counter', który zawiera chmurkę stanu oznaczoną jako 'count' z wartością 3. Środkowa sekcja ma ten sam komponent nadrzędny 'div', ale komponent potomny został teraz usunięty, co zostało zaznaczone żółtym obrazkiem 'puf'. Trzecia sekcja ma znowu ten sam komponent nadrzędny 'div', teraz z nowym potomkiem oznaczonym jako 'p', wyróżnionym na żółto."> -When `Counter` changes to `p`, the `Counter` is deleted and the `p` is added +Gdy komponent `Counter` zmienia się na element `p`, `Counter` zostaje usunięty, a `p` zostaje dodany. </Diagram> @@ -575,15 +575,15 @@ When `Counter` changes to `p`, the `Counter` is deleted and the `p` is added <DiagramGroup> -<Diagram name="preserving_state_diff_pt2" height={290} width={753} alt="Diagram with three sections, with an arrow transitioning each section in between. The first section contains a React component labeled 'p'. The middle section has the same 'div' parent, but the child component has now been deleted, indicated by a yellow 'proof' image. The third section has the same 'div' parent again, now with a new child labeled 'Counter' containing a state bubble labeled 'count' with value 0, highlighted in yellow."> +<Diagram name="preserving_state_diff_pt2" height={290} width={753} alt="Diagram z trzema sekcjami, z strzałkami przechodzącymi między sekcjami. Pierwsza sekcja zawiera komponent React o nazwie `p`. Środkowa sekcja ma ten sam komponent `div`, ale komponent dziecka został teraz usunięty, co jest wskazane przez żółty obrazek z napisem 'puf'. Trzecia sekcja znowu zawiera ten sam komponent `div`, ale teraz z nowym potomkiem oznaczonym jako `Counter`, które zawiera chmurkę stanu o nazwie `count` z wartością 0, wyróżniony na żółto."> -When switching back, the `p` is deleted and the `Counter` is added +Kiedy przełączasz z powrotem, `p` jest usuwany, a `Counter` jest dodawany </Diagram> </DiagramGroup> -Also, **when you render a different component in the same position, it resets the state of its entire subtree.** To see how this works, increment the counter and then tick the checkbox: +Również **renderowanie innego komponentu na tej samej pozycji resetuje stan całego jego poddrzewa.** Aby zobaczyć, jak to działa, zwiększ licznik, a następnie zaznacz pole wyboru: <Sandpack> @@ -611,7 +611,7 @@ export default function App() { setIsFancy(e.target.checked) }} /> - Use fancy styling + Użyj wyszukanego stylu </label> </div> ); @@ -637,7 +637,7 @@ function Counter({ isFancy }) { > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -672,13 +672,13 @@ label { </Sandpack> -The counter state gets reset when you click the checkbox. Although you render a `Counter`, the first child of the `div` changes from a `div` to a `section`. When the child `div` was removed from the DOM, the whole tree below it (including the `Counter` and its state) was destroyed as well. +Stan licznika zostaje zresetowany, gdy klikniesz pole wyboru. Chociaż renderujesz komponent `Counter`, pierwszy potomek elementu `div` zmienia się z `div` na `section`. Kiedy potomek `div` został usunięty z drzewa DOM, całe drzewo poniżej niego (w tym komponent `Counter` i jego stan) zostało również zniszczone. <DiagramGroup> -<Diagram name="preserving_state_diff_same_pt1" height={350} width={794} alt="Diagram with three sections, with an arrow transitioning each section in between. The first section contains a React component labeled 'div' with a single child labeled 'section', which has a single child labeled 'Counter' containing a state bubble labeled 'count' with value 3. The middle section has the same 'div' parent, but the child components have now been deleted, indicated by a yellow 'proof' image. The third section has the same 'div' parent again, now with a new child labeled 'div', highlighted in yellow, also with a new child labeled 'Counter' containing a state bubble labeled 'count' with value 0, all highlighted in yellow."> +<Diagram name="preserving_state_diff_same_pt1" height={350} width={794} alt="Diagram z trzema sekcjami, pomiędzy którymi znajduje się strzałka wskazująca przejście. Pierwsza sekcja zawiera komponent reactowy o nazwie 'div' z jednym potomkiem o nazwie 'section', który ma jednego potomka o nazwie 'Counter' z chmurką stanu oznaczoną jako 'count' z wartością 3. Środkowa sekcja ma tego samego rodzica 'div', ale komponenty potomne zostały usunięte, co wskazuje żółty obrazek 'puf'. Trzecia sekcja ponownie ma tego samego rodzica 'div', teraz z nowym potomkiem o nazwie 'div', podświetlonym na żółto, również z nowym potomkiem o nazwie 'Counter' z chmurką stanu oznaczoną jako 'count' z wartością 0, wszystko podświetlone na żółto."> -When `section` changes to `div`, the `section` is deleted and the new `div` is added +Gdy element `section` zmienia się na `div`, `section` zostaje usunięty, a nowy `div` zostaje dodany. </Diagram> @@ -686,21 +686,21 @@ When `section` changes to `div`, the `section` is deleted and the new `div` is a <DiagramGroup> -<Diagram name="preserving_state_diff_same_pt2" height={350} width={794} alt="Diagram with three sections, with an arrow transitioning each section in between. The first section contains a React component labeled 'div' with a single child labeled 'div', which has a single child labeled 'Counter' containing a state bubble labeled 'count' with value 0. The middle section has the same 'div' parent, but the child components have now been deleted, indicated by a yellow 'proof' image. The third section has the same 'div' parent again, now with a new child labeled 'section', highlighted in yellow, also with a new child labeled 'Counter' containing a state bubble labeled 'count' with value 0, all highlighted in yellow."> +<Diagram name="preserving_state_diff_same_pt2" height={350} width={794} alt="Diagram z trzema sekcjami, pomiędzy którymi znajduje się strzałka wskazująca przejście. Pierwsza sekcja zawiera komponent reactowy o nazwie 'div' z jednym potomkiem o nazwie 'div', który ma jednego potomka o nazwie 'Counter' z chmurką stanu oznaczoną jako 'count' z wartością 0. Środkowa sekcja ma tego samego rodzica 'div', ale komponenty potomne zostały usunięte, co wskazuje żółty obrazek 'puf'. Trzecia sekcja ponownie ma tego samego rodzica 'div', teraz z nowym potomkiem o nazwie 'section', podświetlonym na żółto, również z nowym potomkiem o nazwie 'Counter' z chmurką stanu oznaczoną jako 'count' z wartością 0, wszystko podświetlone na żółto."> -When switching back, the `div` is deleted and the new `section` is added +Gdy następuje odwrotna sytuacja, `div` zostaje usunięty, a nowy element `section` zostaje dodany. </Diagram> </DiagramGroup> -As a rule of thumb, **if you want to preserve the state between re-renders, the structure of your tree needs to "match up"** from one render to another. If the structure is different, the state gets destroyed because React destroys state when it removes a component from the tree. +Ogólna zasada jest taka, że **jeśli chcesz zachować stan pomiędzy renderowaniami, struktura drzewa musi "pasować"** między jednym a drugim renderowaniem. Jeśli struktura jest inna, stan zostaje zniszczony, ponieważ React usuwa stan, gdy usuwa komponent z drzewa. <Pitfall> -This is why you should not nest component function definitions. +Oto dlaczego nie powinno się zagnieżdżać definicji funkcji komponentów. -Here, the `MyTextField` component function is defined *inside* `MyComponent`: +Tutaj funkcja komponentu `MyTextField` jest zdefiniowana *wewnątrz* komponentu `MyComponent`: <Sandpack> @@ -726,7 +726,7 @@ export default function MyComponent() { <MyTextField /> <button onClick={() => { setCounter(counter + 1) - }}>Clicked {counter} times</button> + }}>Naciśnięto {counter} razy</button> </> ); } @@ -735,13 +735,13 @@ export default function MyComponent() { </Sandpack> -Every time you click the button, the input state disappears! This is because a *different* `MyTextField` function is created for every render of `MyComponent`. You're rendering a *different* component in the same position, so React resets all state below. This leads to bugs and performance problems. To avoid this problem, **always declare component functions at the top level, and don't nest their definitions.** +Za każdym razem, gdy klikasz przycisk, stan pola wejściowego znika! Dzieje się tak, ponieważ za każdym razem, gdy renderowany jest komponent `MyComponent`, tworzona jest *inna* funkcja `MyTextField`. Renderujesz *inny* komponent na tej samej pozycji, więc React resetuje cały stan poniżej. Prowadzi to do błędów i problemów z wydajnością. Aby uniknąć tego problemu, **zawsze deklaruj funkcje komponentów na najwyższym poziomie i nie zagnieżdżaj ich definicji.** </Pitfall> -## Resetting state at the same position {/*resetting-state-at-the-same-position*/} +## Resetowanie stanu na tej samej pozycji {/*resetting-state-at-the-same-position*/} -By default, React preserves state of a component while it stays at the same position. Usually, this is exactly what you want, so it makes sense as the default behavior. But sometimes, you may want to reset a component's state. Consider this app that lets two players keep track of their scores during each turn: +Domyślnie React zachowuje stan komponentu, dopóki pozostaje on na tej samej pozycji. Zazwyczaj jest to dokładnie to, czego oczekujesz, więc to domyślne zachowanie ma sens. Czasami jednak możesz chcieć zresetować stan komponentu. Rozważ poniższą aplikację, która pozwala dwóm graczom śledzić swoje wyniki podczas każdej tury: <Sandpack> @@ -760,7 +760,7 @@ export default function Scoreboard() { <button onClick={() => { setIsPlayerA(!isPlayerA); }}> - Next player! + Następny gracz! </button> </div> ); @@ -781,9 +781,9 @@ function Counter({ person }) { onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > - <h1>{person}'s score: {score}</h1> + <h1>Wynik gracza {person}: {score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -811,19 +811,19 @@ h1 { </Sandpack> -Currently, when you change the player, the score is preserved. The two `Counter`s appear in the same position, so React sees them as *the same* `Counter` whose `person` prop has changed. +Obecnie, gdy zmieniasz gracza, wynik jest zachowany. Dwa komponenty licznika `Counter` pojawiają się na tej samej pozycji, więc React widzi je jako *ten sam* komponent `Counter`, w którym zmieniła się właściwość `person`. -But conceptually, in this app they should be two separate counters. They might appear in the same place in the UI, but one is a counter for Taylor, and another is a counter for Sarah. +Ale w tym przypadku, koncepcyjnie powinny to być dwa osobne liczniki. Mogą pojawiać się w tym samym miejscu w interfejsie użytkownika, ale jeden z nich to licznik dla Taylora, a drugi dla Sarah. -There are two ways to reset state when switching between them: +Istnieją dwa sposoby na zresetowanie stanu podczas przełączania się między licznikami: -1. Render components in different positions -2. Give each component an explicit identity with `key` +1. Renderowanie komponentów na różnych pozycjach +2. Nadanie każdemu komponentowi konkretnej tożsamości za pomocą klucza `key` -### Option 1: Rendering a component in different positions {/*option-1-rendering-a-component-in-different-positions*/} +### Opcja 1: Renderowanie komponentu na różnych pozycjach {/*option-1-rendering-a-component-in-different-positions*/} -If you want these two `Counter`s to be independent, you can render them in two different positions: +Jeśli chcesz, aby te dwa komponenty `Counter` były niezależne, możesz wyrenderować je na dwóch różnych pozycjach: <Sandpack> @@ -843,7 +843,7 @@ export default function Scoreboard() { <button onClick={() => { setIsPlayerA(!isPlayerA); }}> - Next player! + Następny gracz! </button> </div> ); @@ -864,9 +864,9 @@ function Counter({ person }) { onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > - <h1>{person}'s score: {score}</h1> + <h1>Wynik gracza {person}: {score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -894,42 +894,42 @@ h1 { </Sandpack> -* Initially, `isPlayerA` is `true`. So the first position contains `Counter` state, and the second one is empty. -* When you click the "Next player" button the first position clears but the second one now contains a `Counter`. +* Początkowo, `isPlayerA` ma wartość `true`. W związku z tym pierwsza pozycja zawiera komponent `Counter`, a druga jest pusta. +* Kiedy klikniesz przycisk "Następny gracz", pierwsza pozycja się opróżnia, a w drugiej pojawia się komponent `Counter`. <DiagramGroup> -<Diagram name="preserving_state_diff_position_p1" height={375} width={504} alt="Diagram with a tree of React components. The parent is labeled 'Scoreboard' with a state bubble labeled isPlayerA with value 'true'. The only child, arranged to the left, is labeled Counter with a state bubble labeled 'count' and value 0. All of the left child is highlighted in yellow, indicating it was added."> +<Diagram name="preserving_state_diff_position_p1" height={375} width={504} alt="Diagram przedstawiający drzewo komponentów React. Rodzic jest oznaczony jako 'Scoreboard' z chmurką stanu o nazwie isPlayerA i wartością 'true'. Jedyny potomek, umieszczony po lewej stronie, jest oznaczony jako Counter z chmurką stanu o nazwie 'count' i wartością 0. Cały lewy potomek jest podświetlony na żółto, co wskazuje, że został dodany."> -Initial state +Stan początkowy </Diagram> -<Diagram name="preserving_state_diff_position_p2" height={375} width={504} alt="Diagram with a tree of React components. The parent is labeled 'Scoreboard' with a state bubble labeled isPlayerA with value 'false'. The state bubble is highlighted in yellow, indicating that it has changed. The left child is replaced with a yellow 'poof' image indicating that it has been deleted and there is a new child on the right, highlighted in yellow indicating that it was added. The new child is labeled 'Counter' and contains a state bubble labeled 'count' with value 0."> +<Diagram name="preserving_state_diff_position_p2" height={375} width={504} alt="Diagram przedstawiający drzewo komponentów React. Rodzic jest oznaczony jako 'Scoreboard' z chmurką stanu o nazwie isPlayerA i wartością 'false'. Chmurka stanu jest podświetlona na żółto, co wskazuje, że jej wartość się zmieniła. Lewy potomek został zastąpiony żółtym obrazkiem 'puf', co oznacza, że został usunięty, a po prawej stronie pojawił się nowy potomek, podświetlony na żółto, co oznacza, że został dodany. Nowy potomek jest oznaczony jako 'Counter' i zawiera chmurkę stanu o nazwie 'count' i wartości 0."> -Clicking "next" +Kliknięcie "następny" </Diagram> -<Diagram name="preserving_state_diff_position_p3" height={375} width={504} alt="Diagram with a tree of React components. The parent is labeled 'Scoreboard' with a state bubble labeled isPlayerA with value 'true'. The state bubble is highlighted in yellow, indicating that it has changed. There is a new child on the left, highlighted in yellow indicating that it was added. The new child is labeled 'Counter' and contains a state bubble labeled 'count' with value 0. The right child is replaced with a yellow 'poof' image indicating that it has been deleted."> +<Diagram name="preserving_state_diff_position_p3" height={375} width={504} alt="Diagram przedstawiający drzewo komponentów React. Rodzic jest oznaczony jako 'Scoreboard' z chmurką stanu o nazwie isPlayerA i wartości 'true'. Chmurka stanu jest podświetlona na żółto, co wskazuje, że jej wartość się zmieniła. Po lewej stronie pojawił się nowy potomek, podświetlony na żółto, co oznacza, że został dodany. Nowy potomek jest oznaczony jako 'Counter' i zawiera chmurkę stanu o nazwie 'count' i wartości 0. Prawy potomek został zastąpiony żółtym obrazkiem 'puf', co oznacza, że został usunięty."> -Clicking "next" again +Kliknięcie "następny" ponownie </Diagram> </DiagramGroup> -Each `Counter`'s state gets destroyed each time it's removed from the DOM. This is why they reset every time you click the button. +Stan każdego komponentu `Counter` jest niszczony za każdym razem, gdy jest usuwany z drzewa DOM. To dlatego stany te resetują się za każdym razem, gdy klikniesz przycisk. -This solution is convenient when you only have a few independent components rendered in the same place. In this example, you only have two, so it's not a hassle to render both separately in the JSX. +To rozwiązanie jest wygodne, gdy masz tylko kilka niezależnych komponentów renderowanych w tym samym miejscu. W tym przykładzie są tylko dwa, więc nie ma problemu z renderowaniem obu osobno w składni JSX. -### Option 2: Resetting state with a key {/*option-2-resetting-state-with-a-key*/} +### Opcja 2: Resetowanie stanu za pomocą klucza (ang. _key_) {/*option-2-resetting-state-with-a-key*/} -There is also another, more generic, way to reset a component's state. +Istnieje także inny, bardziej ogólny sposób na zresetowanie stanu komponentu. -You might have seen `key`s when [rendering lists.](/learn/rendering-lists#keeping-list-items-in-order-with-key) Keys aren't just for lists! You can use keys to make React distinguish between any components. By default, React uses order within the parent ("first counter", "second counter") to discern between components. But keys let you tell React that this is not just a *first* counter, or a *second* counter, but a specific counter--for example, *Taylor's* counter. This way, React will know *Taylor's* counter wherever it appears in the tree! +Przy [renderowaniu list](/learn/rendering-lists#keeping-list-items-in-order-with-key) można zauważyć użycie kluczy. Klucze te nie są tylko dla list! Możesz użyć kluczy, aby pomóc Reactowi rozróżnić dowolne komponenty. Domyślnie React używa kolejności w obrębie rodzica ("pierwszy licznik", "drugi licznik"), aby odróżnić komponenty. Jednak klucze pozwalają powiedzieć Reactowi, że to nie jest tylko *pierwszy* licznik czy *drugi* licznik, ale jakiś konkretny licznik - na przykład *licznik Taylora*. W ten sposób React będzie wiedział, że to licznik *Taylora*, niezależnie od tego, gdzie pojawi się on w drzewie! -In this example, the two `<Counter />`s don't share state even though they appear in the same place in JSX: +W tym przykładzie dwa komponenty `<Counter />` nie dzielą stanu, mimo że pojawiają się w tym samym miejscu w składni JSX: <Sandpack> @@ -948,7 +948,7 @@ export default function Scoreboard() { <button onClick={() => { setIsPlayerA(!isPlayerA); }}> - Next player! + Następny gracz! </button> </div> ); @@ -969,9 +969,9 @@ function Counter({ person }) { onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > - <h1>{person}'s score: {score}</h1> + <h1>Wynika gracza {person}: {score}</h1> <button onClick={() => setScore(score + 1)}> - Add one + Dodaj jeden </button> </div> ); @@ -999,7 +999,7 @@ h1 { </Sandpack> -Switching between Taylor and Sarah does not preserve the state. This is because **you gave them different `key`s:** +Przełączanie między graczami Taylor a Sarah nie zachowuje ich stanu. Dzieje się tak, ponieważ **przypisano im różne klucze `key`**: ```js {isPlayerA ? ( @@ -1009,19 +1009,19 @@ Switching between Taylor and Sarah does not preserve the state. This is because )} ``` -Specifying a `key` tells React to use the `key` itself as part of the position, instead of their order within the parent. This is why, even though you render them in the same place in JSX, React sees them as two different counters, and so they will never share state. Every time a counter appears on the screen, its state is created. Every time it is removed, its state is destroyed. Toggling between them resets their state over and over. +Określenie klucza `key` mówi Reactowi, aby użył jego samego jako części pozycji, zamiast polegać na kolejności w obrębie rodzica. Dlatego, chociaż renderujesz je w tym samym miejscu w składni JSX, React postrzega je jako dwa różne liczniki, więc nigdy nie będą one dzielić stanu. Za każdym razem, gdy licznik pojawia się na ekranie, jego stan jest tworzony. Za każdym razem, gdy jest usuwany, jego stan jest niszczony. Przełączanie między komponentami resetuje ich stan w kółko. <Note> -Remember that keys are not globally unique. They only specify the position *within the parent*. +Pamiętaj, że klucze nie są unikalne globalnie. Określają one pozycję tylko *w obrębie rodzica*. </Note> -### Resetting a form with a key {/*resetting-a-form-with-a-key*/} +### Resetowanie formularza za pomocą klucza {/*resetting-a-form-with-a-key*/} -Resetting state with a key is particularly useful when dealing with forms. +Resetowanie stanu za pomocą klucza jest szczególnie przydatne podczas pracy z formularzami. -In this chat app, the `<Chat>` component contains the text input state: +W poniższej aplikacji czatu, komponent `<Chat>` zawiera stan dla pola tekstowego: <Sandpack> @@ -1084,11 +1084,11 @@ export default function Chat({ contact }) { <section className="chat"> <textarea value={text} - placeholder={'Chat to ' + contact.name} + placeholder={'Czat z ' + contact.name} onChange={e => setText(e.target.value)} /> <br /> - <button>Send to {contact.email}</button> + <button>Wyślij do {contact.email}</button> </section> ); } @@ -1116,17 +1116,17 @@ textarea { </Sandpack> -Try entering something into the input, and then press "Alice" or "Bob" to choose a different recipient. You will notice that the input state is preserved because the `<Chat>` is rendered at the same position in the tree. +Spróbuj wpisać coś w polu tekstowym, a następnie wybierz innego odbiorcę, klikając „Alice” lub „Bob”. Zauważ, że stan pola tekstowego jest zachowywany, ponieważ komponent `<Chat>` jest renderowany na tej samej pozycji w drzewie komponentów. -**In many apps, this may be the desired behavior, but not in a chat app!** You don't want to let the user send a message they already typed to a wrong person due to an accidental click. To fix it, add a `key`: +**W wielu aplikacjach może to być pożądane zachowanie, ale nie w aplikacji czatu!** Nie chcesz, aby użytkownik wysłał wiadomość do niewłaściwej osoby z powodu przypadkowego kliknięcia. Aby to naprawić, dodaj klucz `key`: ```js <Chat key={to.id} contact={to} /> ``` -This ensures that when you select a different recipient, the `Chat` component will be recreated from scratch, including any state in the tree below it. React will also re-create the DOM elements instead of reusing them. +To rozwiązanie zapewnia, że kiedy wybierzesz innego odbiorcę, komponent `Chat` zostanie stworzony od nowa, łącznie z całym stanem w drzewie poniżej niego. React również ponownie utworzy elementy drzewa DOM zamiast ponownie ich użyć. -Now switching the recipient always clears the text field: +Teraz zmiana odbiorcy zawsze wyczyści pole tekstowe: <Sandpack> @@ -1189,11 +1189,11 @@ export default function Chat({ contact }) { <section className="chat"> <textarea value={text} - placeholder={'Chat to ' + contact.name} + placeholder={'Czatuj z ' + contact.name} onChange={e => setText(e.target.value)} /> <br /> - <button>Send to {contact.email}</button> + <button>Wyślij do {contact.email}</button> </section> ); } @@ -1223,24 +1223,24 @@ textarea { <DeepDive> -#### Preserving state for removed components {/*preserving-state-for-removed-components*/} +#### Zachowywanie stanu dla usuniętych komponentów {/*preserving-state-for-removed-components*/} -In a real chat app, you'd probably want to recover the input state when the user selects the previous recipient again. There are a few ways to keep the state "alive" for a component that's no longer visible: +W prawdziwej aplikacji czatu, prawdopodobnie chcesz odzyskać stan wprowadzonego tekstu, gdy użytkownik ponownie wybierze poprzedniego odbiorcę. Istnieje kilka sposobów na to, aby stan komponentu, który nie jest już widoczny, pozostał zachowany: -- You could render _all_ chats instead of just the current one, but hide all the others with CSS. The chats would not get removed from the tree, so their local state would be preserved. This solution works great for simple UIs. But it can get very slow if the hidden trees are large and contain a lot of DOM nodes. -- You could [lift the state up](/learn/sharing-state-between-components) and hold the pending message for each recipient in the parent component. This way, when the child components get removed, it doesn't matter, because it's the parent that keeps the important information. This is the most common solution. -- You might also use a different source in addition to React state. For example, you probably want a message draft to persist even if the user accidentally closes the page. To implement this, you could have the `Chat` component initialize its state by reading from the [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), and save the drafts there too. +- Możesz renderować _wszystkie_ czaty zamiast tylko aktualnie wybranego i ukryć pozostałe za pomocą stylów CSS. Czat nie zostanie usunięty z drzewa, więc jego lokalny stan będzie zachowany. To rozwiązanie działa świetnie dla prostych interfejsów, ale może stać się powolne, jeśli ukryte drzewa będą duże i będą zawierały dużo węzłów drzewa DOM. +- Możesz [przenieść stan wyżej](/learn/sharing-state-between-components) i przechowywać wiadomości oczekujące dla każdego odbiorcy w komponencie nadrzędnym. Dzięki temu, nawet gdy komponenty podrzędne zostaną usunięte, nie ma to znaczenia, ponieważ to rodzic przechowuje istotne informacje. Jest to najczęściej stosowane rozwiązanie. +- Możesz również użyć innego sposobu zamiast stanu Reacta. Na przykład, być może chcesz, aby wersja robocza wiadomości przetrwała nawet w przypadku omyłkowego zamknięcia strony przez użytkownika. Aby to zaimplementować, komponent `Chat` mógłby inicjalizować swój stan, odczytując go z [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), a także zapisywać tam wersje robocze wiadomości. -No matter which strategy you pick, a chat _with Alice_ is conceptually distinct from a chat _with Bob_, so it makes sense to give a `key` to the `<Chat>` tree based on the current recipient. +Bez względu na to, którą strategię wybierzesz, czat _z Alicją_ jest koncepcyjnie inny niż czat _z Bobem_, więc sensowne jest przypisanie klucza `key` do drzewa `<Chat>` na podstawie aktualnego odbiorcy. </DeepDive> <Recap> -- React keeps state for as long as the same component is rendered at the same position. -- State is not kept in JSX tags. It's associated with the tree position in which you put that JSX. -- You can force a subtree to reset its state by giving it a different key. -- Don't nest component definitions, or you'll reset state by accident. +- React utrzymuje stan tak długo, jak ten sam komponent jest renderowany w tym samym miejscu. +- Stan nie jest przechowywany w znacznikach JSX. Jest on powiązany z pozycją drzewa, w której umieszczasz ten kod JSX. +- Możesz wymusić zresetowanie stanu poddrzewa, nadając mu inny klucz `key`. +- Nie zagnieżdżaj definicji komponentów, ponieważ przypadkowo zresetujesz stan. </Recap> @@ -1248,9 +1248,9 @@ No matter which strategy you pick, a chat _with Alice_ is conceptually distinct <Challenges> -#### Fix disappearing input text {/*fix-disappearing-input-text*/} +#### Napraw znikający tekst w polu input {/*fix-disappearing-input-text*/} -This example shows a message when you press the button. However, pressing the button also accidentally resets the input. Why does this happen? Fix it so that pressing the button does not reset the input text. +W poniższym przykładzie po naciśnięciu przycisku wyświetlana jest wiadomość. Jednak przypadkowe naciśnięcie przycisku resetuje również pole wprowadzania tekstu. Dlaczego tak się dzieje? Napraw to, aby naciśnięcie przycisku nie resetowało tekstu w polu wprowadzania. <Sandpack> @@ -1262,11 +1262,11 @@ export default function App() { if (showHint) { return ( <div> - <p><i>Hint: Your favorite city?</i></p> + <p><i>Podpowiedź: Twoje ulubione miasto?</i></p> <Form /> <button onClick={() => { setShowHint(false); - }}>Hide hint</button> + }}>Ukryj podpowiedź</button> </div> ); } @@ -1275,7 +1275,7 @@ export default function App() { <Form /> <button onClick={() => { setShowHint(true); - }}>Show hint</button> + }}>Pokaż podpowiedź</button> </div> ); } @@ -1299,9 +1299,9 @@ textarea { display: block; margin: 10px 0; } <Solution> -The problem is that `Form` is rendered in different positions. In the `if` branch, it is the second child of the `<div>`, but in the `else` branch, it is the first child. Therefore, the component type in each position changes. The first position changes between holding a `p` and a `Form`, while the second position changes between holding a `Form` and a `button`. React resets the state every time the component type changes. +Problem polega na tym, że komponent `Form` jest renderowany na różnych pozycjach. W gałęzi `if`, komponent ten jest drugim dzieckiem elementu `<div>`, natomiast w gałęzi `else` jest pierwszym dzieckiem. W związku z tym typ komponentu zmienia się na każdej pozycji. Na pierwszej pozycji występuje naprzemiennie `p` i `Form`, podczas gdy na drugiej pozycji `Form` i `button`. React resetuje stan za każdym razem, gdy typ komponentu zmienia się. -The easiest solution is to unify the branches so that `Form` always renders in the same position: +Najprostszym rozwiązaniem jest ujednolicenie gałęzi tak, aby `Form` zawsze renderował się w tej samej pozycji: <Sandpack> @@ -1313,17 +1313,17 @@ export default function App() { return ( <div> {showHint && - <p><i>Hint: Your favorite city?</i></p> + <p><i>Podpowiedź: Twoje ulubione miasto?</i></p> } <Form /> {showHint ? ( <button onClick={() => { setShowHint(false); - }}>Hide hint</button> + }}>Ukryj podpowiedź</button> ) : ( <button onClick={() => { setShowHint(true); - }}>Show hint</button> + }}>Pokaż podpowiedź</button> )} </div> ); @@ -1347,7 +1347,7 @@ textarea { display: block; margin: 10px 0; } </Sandpack> -Technically, you could also add `null` before `<Form />` in the `else` branch to match the `if` branch structure: +W praktyce, możesz także dodać `null` przed `<Form />` w gałęzi `else`, aby dopasować strukturę w gałęzi `if`: <Sandpack> @@ -1359,11 +1359,11 @@ export default function App() { if (showHint) { return ( <div> - <p><i>Hint: Your favorite city?</i></p> + <p><i>Podpowiedź: Twoje ulubione miasto?</i></p> <Form /> <button onClick={() => { setShowHint(false); - }}>Hide hint</button> + }}>Ukryj podpowiedź</button> </div> ); } @@ -1373,7 +1373,7 @@ export default function App() { <Form /> <button onClick={() => { setShowHint(true); - }}>Show hint</button> + }}>Pokaż podpowiedź</button> </div> ); } @@ -1395,19 +1395,19 @@ textarea { display: block; margin: 10px 0; } </Sandpack> -This way, `Form` is always the second child, so it stays in the same position and keeps its state. But this approach is much less obvious and introduces a risk that someone else will remove that `null`. +W ten sposób komponent `Form` jest zawsze drugim dzieckiem, więc pozostaje w tej samej pozycji i zachowuje swój stan. Ale to podejście jest znacznie mniej oczywiste i wprowadza ryzyko, że ktoś inny usunie stąd `null`. </Solution> -#### Swap two form fields {/*swap-two-form-fields*/} +#### Zamień dwa pola formularza {/*swap-two-form-fields*/} -This form lets you enter first and last name. It also has a checkbox controlling which field goes first. When you tick the checkbox, the "Last name" field will appear before the "First name" field. +Ten formularz pozwala wpisać imię i nazwisko. Ma także pole wyboru kontrolujące, które pole pojawia się jako pierwsze. Kiedy zaznaczysz to pole wyboru, pole „Nazwisko” pojawi się przed polem „Imię”. -It almost works, but there is a bug. If you fill in the "First name" input and tick the checkbox, the text will stay in the first input (which is now "Last name"). Fix it so that the input text *also* moves when you reverse the order. +To rozwiązanie prawie działa, ale jest w nim błąd. Jeśli wypełnisz pole „Imię” i zaznaczysz pole wyboru, tekst pozostanie w pierwszym polu (które teraz jest występuje jako „Nazwisko”). Napraw to tak, aby tekst z pól również zmieniał się miejscami, gdy zmieniasz kolejność. <Hint> -It seems like for these fields, their position within the parent is not enough. Is there some way to tell React how to match up the state between re-renders? +Wydaje się, że dla tych pól sama ich pozycja względem rodzica nie wystarcza. Czy istnieje jakiś sposób, aby powiedzieć Reactowi, jak ma dopasować stan między renderowaniami? </Hint> @@ -1425,22 +1425,22 @@ export default function App() { checked={reverse} onChange={e => setReverse(e.target.checked)} /> - Reverse order + Odwróć kolejność </label> ); if (reverse) { return ( <> - <Field label="Last name" /> - <Field label="First name" /> + <Field label="Nazwisko" /> + <Field label="Imię" /> {checkbox} </> ); } else { return ( <> - <Field label="First name" /> - <Field label="Last name" /> + <Field label="Imię" /> + <Field label="Nazwisko" /> {checkbox} </> ); @@ -1471,7 +1471,7 @@ label { display: block; margin: 10px 0; } <Solution> -Give a `key` to both `<Field>` components in both `if` and `else` branches. This tells React how to "match up" the correct state for either `<Field>` even if their order within the parent changes: +Nadaj klucz `key` obu komponentom `<Field>` w obu gałęziach `if` i `else`. Dzięki temu React będzie wiedział, jak "dopasować" odpowiedni stan dla każdego komponentu `<Field>`, nawet jeśli ich kolejność w rodzicu zmieni się: <Sandpack> @@ -1487,22 +1487,22 @@ export default function App() { checked={reverse} onChange={e => setReverse(e.target.checked)} /> - Reverse order + Odwróć kolejność </label> ); if (reverse) { return ( <> - <Field key="lastName" label="Last name" /> - <Field key="firstName" label="First name" /> + <Field key="lastName" label="Nazwisko" /> + <Field key="firstName" label="Imię" /> {checkbox} </> ); } else { return ( <> - <Field key="firstName" label="First name" /> - <Field key="lastName" label="Last name" /> + <Field key="firstName" label="Imię" /> + <Field key="lastName" label="Nazwisko" /> {checkbox} </> ); @@ -1533,11 +1533,11 @@ label { display: block; margin: 10px 0; } </Solution> -#### Reset a detail form {/*reset-a-detail-form*/} +#### Zresetowanie formularza szczegółów {/*reset-a-detail-form*/} -This is an editable contact list. You can edit the selected contact's details and then either press "Save" to update it, or "Reset" to undo your changes. +Oto edytowalna lista kontaktów. Możesz edytować szczegóły wybranego kontaktu, a następnie nacisnąć "Zapisz", aby zaktualizować lub "Resetuj", aby cofnąć swoje zmiany. -When you select a different contact (for example, Alice), the state updates but the form keeps showing the previous contact's details. Fix it so that the form gets reset when the selected contact changes. +Gdy wybierzesz inny kontakt (na przykład Alice), stan się zaktualizuje, ale formularz nadal będzie pokazywał szczegóły poprzedniego kontaktu. Napraw to tak, aby formularz został zresetowany, gdy zmienia się wybrany kontakt. <Sandpack> @@ -1629,7 +1629,7 @@ export default function EditContact({ initialData, onSave }) { return ( <section> <label> - Name:{' '} + Imię:{' '} <input type="text" value={name} @@ -1652,13 +1652,13 @@ export default function EditContact({ initialData, onSave }) { }; onSave(updatedData); }}> - Save + Zapisz </button> <button onClick={() => { setName(initialData.name); setEmail(initialData.email); }}> - Reset + Resetuj </button> </section> ); @@ -1689,7 +1689,7 @@ button { <Solution> -Give `key={selectedId}` to the `EditContact` component. This way, switching between different contacts will reset the form: +Nadaj klucz `key={selectedId}` komponentowi `EditContact`. W ten sposób, przełączanie się między różnymi kontaktami spowoduje zresetowanie formularza. <Sandpack> @@ -1782,7 +1782,7 @@ export default function EditContact({ initialData, onSave }) { return ( <section> <label> - Name:{' '} + Imię:{' '} <input type="text" value={name} @@ -1805,13 +1805,13 @@ export default function EditContact({ initialData, onSave }) { }; onSave(updatedData); }}> - Save + Zapisz </button> <button onClick={() => { setName(initialData.name); setEmail(initialData.email); }}> - Reset + Resetuj </button> </section> ); @@ -1842,13 +1842,13 @@ button { </Solution> -#### Clear an image while it's loading {/*clear-an-image-while-its-loading*/} +#### Wyczyść obraz podczas ładowania {/*clear-an-image-while-its-loading*/} -When you press "Next", the browser starts loading the next image. However, because it's displayed in the same `<img>` tag, by default you would still see the previous image until the next one loads. This may be undesirable if it's important for the text to always match the image. Change it so that the moment you press "Next", the previous image immediately clears. +Kiedy naciśniesz "Dalej", przeglądarka zaczyna ładować kolejny obraz. Jednak ponieważ jest on wyświetlany w tym samym tagu `<img>`, domyślnie widać poprzedni obraz do czasu załadowania nowego. Może to być niepożądane zachowanie, jeśli ważne jest, aby tekst zawsze pasował do obrazu. Zmień to tak, aby w momencie naciśnięcia "Dalej" poprzedni obraz natychmiast znikał. <Hint> -Is there a way to tell React to re-create the DOM instead of reusing it? +Czy istnieje sposób, aby dać znać Reactowi, żeby tworzył drzewo DOM od nowa zamiast wykorzystywać go ponownie? </Hint> @@ -1873,10 +1873,10 @@ export default function Gallery() { return ( <> <button onClick={handleClick}> - Next + Dalej </button> <h3> - Image {index + 1} of {images.length} + Obraz {index + 1} z {images.length} </h3> <img src={image.src} /> <p> @@ -1887,25 +1887,25 @@ export default function Gallery() { } let images = [{ - place: 'Penang, Malaysia', + place: 'Penang, Malezja', src: 'https://i.imgur.com/FJeJR8M.jpg' }, { - place: 'Lisbon, Portugal', + place: 'Lizbona, Portugalia', src: 'https://i.imgur.com/dB2LRbj.jpg' }, { - place: 'Bilbao, Spain', + place: 'Bilbao, Hiszpania', src: 'https://i.imgur.com/z08o2TS.jpg' }, { place: 'Valparaíso, Chile', src: 'https://i.imgur.com/Y3utgTi.jpg' }, { - place: 'Schwyz, Switzerland', + place: 'Schwyz, Szwajcaria', src: 'https://i.imgur.com/JBbMpWY.jpg' }, { - place: 'Prague, Czechia', + place: 'Praga, Czechy', src: 'https://i.imgur.com/QwUKKmF.jpg' }, { - place: 'Ljubljana, Slovenia', + place: 'Lublana, Słowenia', src: 'https://i.imgur.com/3aIiwfm.jpg' }]; ``` @@ -1918,7 +1918,7 @@ img { width: 150px; height: 150px; } <Solution> -You can provide a `key` to the `<img>` tag. When that `key` changes, React will re-create the `<img>` DOM node from scratch. This causes a brief flash when each image loads, so it's not something you'd want to do for every image in your app. But it makes sense if you want to ensure the image always matches the text. +Możesz dodać klucz `key` do tagu `<img>`. Gdy ten klucz `key` się zmieni, React utworzy od nowa węzeł drzewa DOM dla `<img>`. Spowoduje to krótkie mignięcie podczas ładowania każdego obrazu, więc nie jest to coś, co warto robić dla każdego obrazku w aplikacji. Ma to jednak sens, jeśli chcesz mieć pewność, że obraz zawsze będzie zgodny z tekstem. <Sandpack> @@ -1941,10 +1941,10 @@ export default function Gallery() { return ( <> <button onClick={handleClick}> - Next + Dalej </button> <h3> - Image {index + 1} of {images.length} + Obraz {index + 1} z {images.length} </h3> <img key={image.src} src={image.src} /> <p> @@ -1955,25 +1955,25 @@ export default function Gallery() { } let images = [{ - place: 'Penang, Malaysia', + place: 'Penang, Malezja', src: 'https://i.imgur.com/FJeJR8M.jpg' }, { - place: 'Lisbon, Portugal', + place: 'Lizbona, Portugalia', src: 'https://i.imgur.com/dB2LRbj.jpg' }, { - place: 'Bilbao, Spain', + place: 'Bilbao, Hiszpania', src: 'https://i.imgur.com/z08o2TS.jpg' }, { place: 'Valparaíso, Chile', src: 'https://i.imgur.com/Y3utgTi.jpg' }, { - place: 'Schwyz, Switzerland', + place: 'Schwyz, Szwajcaria', src: 'https://i.imgur.com/JBbMpWY.jpg' }, { - place: 'Prague, Czechia', + place: 'Praga, Czechy', src: 'https://i.imgur.com/QwUKKmF.jpg' }, { - place: 'Ljubljana, Slovenia', + place: 'Lublana, Słowenia', src: 'https://i.imgur.com/3aIiwfm.jpg' }]; ``` @@ -1986,11 +1986,11 @@ img { width: 150px; height: 150px; } </Solution> -#### Fix misplaced state in the list {/*fix-misplaced-state-in-the-list*/} +#### Napraw błędne przypisanie stanu na liście {/*fix-misplaced-state-in-the-list*/} -In this list, each `Contact` has state that determines whether "Show email" has been pressed for it. Press "Show email" for Alice, and then tick the "Show in reverse order" checkbox. You will notice that it's _Taylor's_ email that is expanded now, but Alice's--which has moved to the bottom--appears collapsed. +W tej liście każdy komponent `Contact` ma stan, który określa, czy przycisk "Pokaż email" został dla niego naciśnięty. Naciśnij "Pokaż email" dla Alice, a następnie zaznacz pole wyboru "Wyświetl w odwrotnej kolejności". Zauważ, że to email _Taylora_ jest teraz rozwinięty, a nie email Alice, której kontakt został przeniesiony na dół i jest zwinięty. -Fix it so that the expanded state is associated with each contact, regardless of the chosen ordering. +Napraw to tak, aby stan rozwinięcia był powiązany z każdym kontaktem, niezależnie od wybranego porządku. <Sandpack> @@ -2016,7 +2016,7 @@ export default function ContactList() { setReverse(e.target.checked) }} />{' '} - Show in reverse order + Wyświetl w odwrotnej kolejności </label> <ul> {displayedContacts.map((contact, i) => @@ -2050,7 +2050,7 @@ export default function Contact({ contact }) { <button onClick={() => { setExpanded(!expanded); }}> - {expanded ? 'Hide' : 'Show'} email + {expanded ? 'Ukryj' : 'Pokaż'} email </button> </> ); @@ -2080,16 +2080,16 @@ button { <Solution> -The problem is that this example was using index as a `key`: +Problem polega na tym, że w tym przykładzie użyto indeksu tablicy jako `key`: ```js {displayedContacts.map((contact, i) => <li key={i}> ``` -However, you want the state to be associated with _each particular contact_. +Jednak tu potrzebujesz, aby stan był powiązany z _każdym konkretnym kontaktem_. -Using the contact ID as a `key` instead fixes the issue: +Użycie identyfikatora kontaktu (`contact.id`) jako `key` rozwiązuje ten problem: <Sandpack> @@ -2115,7 +2115,7 @@ export default function ContactList() { setReverse(e.target.checked) }} />{' '} - Show in reverse order + Wyświetl w odwrotnej kolejności </label> <ul> {displayedContacts.map(contact => @@ -2149,7 +2149,7 @@ export default function Contact({ contact }) { <button onClick={() => { setExpanded(!expanded); }}> - {expanded ? 'Hide' : 'Show'} email + {expanded ? 'Ukryj' : 'Pokaż'} email </button> </> ); @@ -2177,7 +2177,7 @@ button { </Sandpack> -State is associated with the tree position. A `key` lets you specify a named position instead of relying on order. +Teraz stan jest powiązany z pozycją w drzewie. Klucz `key` pozwala określić konkretną pozycje z nazwą zamiast polegać na kolejności. </Solution> diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md new file mode 100644 index 000000000..0ae499472 --- /dev/null +++ b/src/content/learn/react-compiler.md @@ -0,0 +1,378 @@ +--- +title: React Compiler +--- + +<Intro> +This page will give you an introduction to React Compiler and how to try it out successfully. +</Intro> + +<Wip> +These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. +</Wip> + +<YouWillLearn> + +* Getting started with the compiler +* Installing the compiler and ESLint plugin +* Troubleshooting + +</YouWillLearn> + +<Note> +React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). + +The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +</Note> + +React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + +The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. + +The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: + +<TerminalBlock> +npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +</TerminalBlock> + +Or, if you're using Yarn: + +<TerminalBlock> +yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +</TerminalBlock> + +If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. + +### What does the compiler do? {/*what-does-the-compiler-do*/} + +In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. + +The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. + +<Note> +React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. +</Note> + +If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. + +<DeepDive> +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `<Parent />` causes many components in its component tree to re-render, even though only `<Parent />` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `<MessageButton>` will re-render whenever `<FriendList>`'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return <NoFriends />; + } + return ( + <div> + <span>{onlineCount} online</span> + {friends.map((friend) => ( + <FriendListCard key={friend.id} friend={friend} /> + ))} + <MessageButton /> + </div> + ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `<FriendListCard />` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `<MessageButton>` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +The compiler can also automatically memoize for expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +</DeepDive> + +### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). + +**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. + +## Getting Started {/*getting-started*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + +### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/} + +React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler. + +<TerminalBlock> +npm install -D eslint-plugin-react-compiler@beta +</TerminalBlock> + +Then, add it to your ESLint config: + +```js +import reactCompiler from 'eslint-plugin-react-compiler' + +export default [ + { + plugins: { + 'react-compiler': reactCompiler, + }, + rules: { + 'react-compiler/react-compiler': 'error', + }, + }, +] +``` + +Or, in the deprecated eslintrc config format: + +```js +module.exports = { + plugins: [ + 'eslint-plugin-react-compiler', + ], + rules: { + 'react-compiler/react-compiler': 'error', + }, +} +``` + +The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. + +<Note> +**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. +</Note> + +### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} + +#### Existing projects {/*existing-projects*/} +The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. + +For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: + +```js {3} +const ReactCompilerConfig = { + sources: (filename) => { + return filename.indexOf('src/path/to/dir') !== -1; + }, +}; +``` + +When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. + +#### New projects {/*new-projects*/} + +If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. + +### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} + +React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. + +<TerminalBlock> +npm install react-compiler-runtime@beta +</TerminalBlock> + +You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: + +```js {3} +// babel.config.js +const ReactCompilerConfig = { + target: '18' // '17' | '18' | '19' +}; + +module.exports = function () { + return { + plugins: [ + ['babel-plugin-react-compiler', ReactCompilerConfig], + ], + }; +}; +``` + +### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} + +React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. + +Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. + +Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). + +Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. + +## Usage {/*installation*/} + +### Babel {/*usage-with-babel*/} + +<TerminalBlock> +npm install babel-plugin-react-compiler@beta +</TerminalBlock> + +The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. + +After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: + +```js {7} +// babel.config.js +const ReactCompilerConfig = { /* ... */ }; + +module.exports = function () { + return { + plugins: [ + ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! + // ... + ], + }; +}; +``` + +`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. + +### Vite {/*usage-with-vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {10} +// vite.config.js +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig(() => { + return { + plugins: [ + react({ + babel: { + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], + // ... + }; +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + +<TerminalBlock> +npm install vite-plugin-babel +</TerminalBlock> + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community Webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + +## Troubleshooting {/*troubleshooting*/} + +To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. + +You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). + +### What does the compiler assume? {/*what-does-the-compiler-assume*/} + +React Compiler assumes that your code: + +1. Is valid, semantic JavaScript. +2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. +3. Follows the [Rules of React](https://react.dev/reference/rules). + +React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). + +### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} + +[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. + +### Something is not working after compilation {/*something-is-not-working-after-compilation*/} +If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. + +Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. + +If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). + +```js {2} +function SuspiciousComponent() { + "use no memo"; // opts out this component from being compiled by React Compiler + // ... +} +``` + +<Note> +#### `"use no memo"` {/*use-no-memo*/} + +`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. + +It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. +</Note> + +When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. + +### Other issues {/*other-issues*/} + +Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md index 13b831f8f..cba4c45a5 100644 --- a/src/content/learn/react-developer-tools.md +++ b/src/content/learn/react-developer-tools.md @@ -60,26 +60,8 @@ Na koniec odśwież stronę w przeglądarce, aby podejrzeć ją w narzędziach d ## Aplikacje mobilne (React Native) {/*mobile-react-native*/} -Narzędzi deweloperskich dla Reacta można z powodzeniem używać również do podglądania aplikacji napisanych w [React Native](https://reactnative.dev/). - -Najprościej jest zainstalować je globalnie: - -```bash -# Yarn -yarn global add react-devtools - -# Npm -npm install -g react-devtools -``` - -Teraz uruchom narzędzia deweloperskie z terminala. - -```bash -react-devtools -``` - -Powinno nastąpić połączenie do lokalnie działającej aplikacji. - -> Jeśli połączenie nie nastąpi w ciągu następnych kilku sekund, spróbuj załadować aplikację ponownie. +Do inspekcji aplikacji zbudowanych w [React Native](https://reactnative.dev/) możesz wykorzystać [React Native DevTools](https://reactnative.dev/docs/react-native-devtools), czyli wbudowany debugger głęboko zintegrowany z React Developer Tools. Wszystkie funkcje w nim działają identycznie jak w przypadku rozszerzenia przeglądarkowego, wliczając w to podświetlanie i zaznaczanie natywnych elementów. [Dowiedz się więcej o debuggowaniu w React Native.](https://reactnative.dev/docs/debugging) + +> W przypadku React Native w wersjach wcześniejszych niż 0.76 zalecamy korzystanie z samodzielnej wersji React DevTools. Więcej na ten temat dowiesz się z powyższej sekcji [Safari i inne przeglądarki](#safari-and-other-browsers). diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md index 4faf18786..6836359d6 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: 'Odwoływanie się do wartości za pomocą referencji' --- <Intro> -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*. +Gdy chcesz, aby komponent "zapamiętał" pewne informacje, ale nie chcesz, aby te informacje [wywoływały ponowne renderowania](/learn/render-and-commit), możesz użyć *referencji* (ang. _reference_, w skrócie _ref_). </Intro> <YouWillLearn> -- 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 +- Jak dodać referencję do komponentu +- Jak zaktualizować wartość referencji +- Czym referencje różnią się od stanu +- Jak bezpiecznie używać referencji </YouWillLearn> -## Adding a ref to your component {/*adding-a-ref-to-your-component*/} +## Dodawanie referencji do komponentu {/*adding-a-ref-to-your-component*/} -You can add a ref to your component by importing the `useRef` Hook from React: +Możesz dodać referencję do swojego komponentu, importując hook `useRef` z Reacta: ```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`: +We wnętrzu swojego komponentu wywołaj hook `useRef`, przekazując jako jedyny argument wartość początkową, do której chcesz się odwoływać. Na przykład, oto referencja do wartości `0`: ```js const ref = useRef(0); ``` -`useRef` returns an object like this: +`useRef` zwraca obiekt o następującej strukturze: ```js { - current: 0 // The value you passed to useRef + current: 0 // Wartość, którą przekazano do useRef } ``` -<Illustration src="/images/docs/illustrations/i_ref.png" alt="An arrow with 'current' written on it stuffed into a pocket with 'ref' written on it." /> +<Illustration src="/images/docs/illustrations/i_ref.png" alt="Strzałka z napisem 'current' włożona do kieszeni z napisem 'ref'" /> -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!) +Możesz uzyskać dostęp do bieżącej wartości tej referencji przez właściwość `ref.current`. Ta wartość jest celowo mutowalna (ang. _mutable_), co oznacza, że możesz ją zarówno odczytywać, jak i zapisywać. To jak taka ukryta kieszeń twojego komponentu, której React nie śledzi. To właśnie sprawia, że jest to "ukryta furtka" pozwalająca wyjść poza jednokierunkowy przepływ danych w Reakcie - więcej na ten temat poniżej! -Here, a button will increment `ref.current` on every click: +Tutaj, przycisk będzie inkrementować `ref.current` przy każdym kliknięciu: <Sandpack> @@ -55,12 +55,12 @@ export default function Counter() { function handleClick() { ref.current = ref.current + 1; - alert('You clicked ' + ref.current + ' times!'); + alert('Kliknięto ' + ref.current + ' razy!'); } return ( <button onClick={handleClick}> - Click me! + Kliknij mnie! </button> ); } @@ -68,20 +68,20 @@ export default function Counter() { </Sandpack> -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. +Referencja wskazuje na liczbę, ale podobnie jak [stan](/learn/state-a-components-memory), możesz wskazać na cokolwiek: ciąg znaków, obiekt, a nawet funkcję. W przeciwieństwie do stanu, referencja to zwykły obiekt javascriptowy z właściwością `current`, którą możesz odczytać i modyfikować. -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! +Zwróć uwagę, że **komponent nie renderuje się ponownie przy każdej inkrementacji.** Podobnie jak stan, referencje są przechowywane przez Reacta między przerenderowaniami. Jednak ustawienie stanu powoduje ponowne renderowanie komponentu, a zmiana referencji - nie! -## Example: building a stopwatch {/*example-building-a-stopwatch*/} +## Przykład: budowanie stopera {/*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:** +Możesz połączyć referencje i stan w jednym komponencie. Na przykład zbudujmy stoper, który użytkownik może uruchomić lub zatrzymać, naciskając przycisk. Aby wyświetlić, ile czasu minęło od momentu naciśnięcia przycisku "Start", musisz śledzić, kiedy przycisk Start został naciśnięty i jaki jest bieżący czas. **Te informacje są używane do renderowania, dlatego będziesz przechowywać je w stanie:** ```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: +Kiedy użytkownik naciśnie "Start", użyjesz metody [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval), aby aktualizować czas co 10 milisekund: <Sandpack> @@ -93,12 +93,12 @@ export default function Stopwatch() { const [now, setNow] = useState(null); function handleStart() { - // Start counting. + // Rozpoczęcie odliczania. setStartTime(Date.now()); setNow(Date.now()); setInterval(() => { - // Update the current time every 10ms. + // Zaktualizowanie bieżącego czasu co 10 ms. setNow(Date.now()); }, 10); } @@ -110,7 +110,7 @@ export default function Stopwatch() { return ( <> - <h1>Time passed: {secondsPassed.toFixed(3)}</h1> + <h1>Minęło: {secondsPassed.toFixed(3)}</h1> <button onClick={handleStart}> Start </button> @@ -121,7 +121,7 @@ export default function Stopwatch() { </Sandpack> -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:** +Kiedy przycisk "Stop" zostanie naciśnięty, musisz anulować istniejący interwał, aby przestał aktualizować zmienną stanu `now`. Możesz to zrobić, wywołując metodę [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), ale musisz przekazać mu identyfikator interwału, który został wcześniej zwrócony przez wywołanie metody `setInterval` po naciśnięciu przycisku Start. Musisz przechować identyfikator interwału w jakimś miejscu. **Ponieważ identyfikator interwału nie jest używany do renderowania, możesz przechować go w referencji:** <Sandpack> @@ -154,7 +154,7 @@ export default function Stopwatch() { return ( <> - <h1>Time passed: {secondsPassed.toFixed(3)}</h1> + <h1>Minęło: {secondsPassed.toFixed(3)}</h1> <button onClick={handleStart}> Start </button> @@ -168,20 +168,20 @@ export default function Stopwatch() { </Sandpack> -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. +Jeśli dana informacja jest wykorzystywana podczas renderowania, przechowuj ją w stanie. Kiedy informacja jest potrzebna tylko dla procedur obsługi zdarzeń i jej zmiana nie wymaga ponownego renderowania, użycie referencji może być bardziej wydajne. -## Differences between refs and state {/*differences-between-refs-and-state*/} +## Różnice między referencjami a stanem {/*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: +Możesz pomyśleć, że referencje wydają się mniej "rygorystyczne" niż stan – na przykład pozwalają na mutowanie wartości bez konieczności używania funkcji do ustawiania stanu. Jednak w większości przypadków będziesz chcieć używać stanu. Referencje to "ukryte furtki", które rzadko będziesz wykorzystywać. Oto porównanie stanu i referencji: -| 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. +| refs | state | +|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| +| `useRef(initialValue)` zwraca `{ current: initialValue }` | `useState(initialValue)` zwraca bieżącą wartość zmiennej stanu oraz funkcję ustawiającą stan (`[value, setValue]`) | +| Nie wywołuje ponownego renderowania, gdy ją zmienisz. | Wywołuje ponowne renderowanie, gdy go zmienisz. | +| Mutowalny - możesz modyfikować i aktualizować wartość `current` poza procesem renderowania. | Niemutowalny - musisz używać funkcji ustawiającej stan, aby modyfikować zmienne stanu i zainicjować kolejne renderowanie. | +| Nie powinno się odczytywać (ani zapisywać) wartości `current` podczas renderowania. | Możesz odczytać stan w dowolnym momencie. Jednak każde renderowanie ma swoją własną [migawkę](/learn/state-as-a-snapshot) stanu, która nie zmienia się. | -Here is a counter button that's implemented with state: +Oto przycisk licznika zaimplementowany za pomocą stanu: <Sandpack> @@ -197,7 +197,7 @@ export default function Counter() { return ( <button onClick={handleClick}> - You clicked {count} times + Kliknięto {count} razy </button> ); } @@ -205,9 +205,9 @@ export default function Counter() { </Sandpack> -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. +Ponieważ wartość `count` jest wyświetlana, ma sens użycie zmiennej stanu do jej przechowywania. Kiedy wartość licznika jest ustawiana za pomocą `setCount()`, React ponownie renderuje komponent, a ekran jest aktualizowany, aby odzwierciedlić nową wartość licznika. -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**: +Gdyby spróbować zaimplementować to za pomocą referencji, React nigdy nie przerenderowałby ponownie komponentu, więc zmiana licznika nie byłaby nigdy widoczna! Zauważ, że kliknięcie tego przycisku **nie aktualizuje jego tekstu**: <Sandpack> @@ -218,13 +218,13 @@ export default function Counter() { let countRef = useRef(0); function handleClick() { - // This doesn't re-render the component! + // To nie przerenderowuje komponentu! countRef.current = countRef.current + 1; } return ( <button onClick={handleClick}> - You clicked {countRef.current} times + Kliknięto {countRef.current} razy </button> ); } @@ -232,68 +232,68 @@ export default function Counter() { </Sandpack> -This is why reading `ref.current` during render leads to unreliable code. If you need that, use state instead. +Dlatego odczytywanie `ref.current` podczas renderowania prowadzi do niepewnego kodu. Jeśli tego potrzebujesz, użyj stanu zamiast referencji. <DeepDive> -#### How does useRef work inside? {/*how-does-use-ref-work-inside*/} +#### Jak działa useRef wewnątrz? {/*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: +Chociaż zarówno `useState`, jak i `useRef` są udostępniane przez Reacta, w zasadzie `useRef` mogłoby być zaimplementowane na bazie `useState`. Możesz sobie wyobrazić, że wewnątrz Reacta, `useRef` jest zaimplementowane w ten sposób: ```js -// Inside of React +// Wewnątrz Reacta 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! +Podczas pierwszego renderowania, `useRef` zwraca `{ current: initialValue }`. Ten obiekt jest przechowywany przez Reacta, więc podczas następnego renderowania zostanie zwrócony ten sam obiekt. Zauważ, że w tym przykładzie funkcja ustawiająca stan nie jest używana. Jest to zbędne, ponieważ `useRef` zawsze musi zwracać ten sam obiekt! -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 zapewnia wbudowaną wersję `useRef`, ponieważ jest to na tyle powszechne w użyciu. Możesz jednak traktować to jako zwykłą zmienną stanu bez funkcji ustawiającej. Jeśli znasz programowanie obiektowe, referencje mogą przypominać ci pola instancji, ale zamiast `this.something` napiszesz `somethingRef.current`. </DeepDive> -## When to use refs {/*when-to-use-refs*/} +## Kiedy używać referencji {/*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: +Zwykle będziesz używać referencji, gdy twój komponent będzie musiał "wyjść poza" Reacta i komunikować się z zewnętrznymi API, najczęściej z API przeglądarki, które nie wpływa na wygląd komponentu. Oto kilka tych rzadkich przypadków użycia: -- 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. +- Przechowywanie [identyfikatorów timeoutów](https://developer.mozilla.org/docs/Web/API/setTimeout) +- Przechowywanie i manipulowanie [elementami DOM](https://developer.mozilla.org/docs/Web/API/Element), co omówimy na [następnej stronie](/learn/manipulating-the-dom-with-refs) +- Przechowywanie obiektów, które nie wpływają na obliczanie JSXa. -If your component needs to store some value, but it doesn't impact the rendering logic, choose refs. +Jeśli twój komponent musi przechować wartość, która nie wpływa na logikę renderowania, użyj referencji. -## Best practices for refs {/*best-practices-for-refs*/} +## Najlepsze praktyki dotyczące referencji {/*best-practices-for-refs*/} -Following these principles will make your components more predictable: +Stosowanie się do tych zasad sprawi, że twoje komponenty będą bardziej przewidywalne: -- **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.) +- **Traktuj referencje jako ukrytą furtkę.** Referencje przydają się podczas pracy z systemami zewnętrznymi lub API przeglądarki. Jeśli większość logiki aplikacji i przepływu danych opiera się na referencjach, warto przemyśleć swoje podejście. +- **Nie odczytuj ani nie zapisuj `ref.current` podczas renderowania.** Jeśli jakaś informacja jest potrzebna podczas renderowania, użyj [stanu](/learn/state-a-components-memory). Ponieważ React nie wie, kiedy `ref.current` się zmienia, nawet odczytanie go podczas renderowania sprawia, że zachowanie komponentu staje się trudne do przewidzenia. Jedynym wyjątkiem od tej zasady jest kod taki jak `if (!ref.current) ref.current = new Thing()`, który ustawia referencję tylko raz podczas pierwszego renderowania. -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: +Ograniczenia stanu w Reakcie nie dotyczą referencji. Na przykład, stan działa jak [migawka dla każdego renderowania](/learn/state-as-a-snapshot) i [nie aktualizuje się synchronicznie.](/learn/queueing-a-series-of-state-updates) Jednak gdy zmieniasz bieżącą wartość referencji, zmiana następuje natychmiastowo: ```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. +Dzieje się tak, ponieważ **referencja sama w sobie jest zwykłym obiektem javascriptowym**, więc tak też się zachowuje. -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. +Nie musisz również martwić się o [unikanie mutacji](/learn/updating-objects-in-state) podczas pracy z referencją. Dopóki obiekt, który mutujesz, nie jest używany do renderowania, React nie interesuje się tym, co robisz z referencją lub jej zawartością. -## Refs and the DOM {/*refs-and-the-dom*/} +## Referencje i 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 `<div ref={myRef}>`, React will put the corresponding DOM element into `myRef.current`. Once the element is removed from the DOM, React will update `myRef.current` to be `null`. You can read more about this in [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs) +Referencję możesz przypisać do dowolnej wartości. Jednak najczęstszym przypadkiem użycia referencji jest dostęp do elementu DOM. Jest to przydatne, jeśli na przykład chcesz programowo ustawić fokus na polu wejściowym. Jeśli przekażesz referencję do atrybutu `ref` w JSX, jak na przykład `<div ref={myRef}>`, React umieści odpowiadający element DOM w `myRef.current`. Gdy element zostanie usunięty z DOM, React zaktualizuje `myRef.current`, ustawiając go na `null`. Możesz przeczytać więcej na ten temat w rozdziale [Manipulowanie DOM przy użyciu referencji](/learn/manipulating-the-dom-with-refs). <Recap> -- 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. +- Referencje to "ukryte furtki" do przechowywania wartości, które nie są używane do renderowania. Nie będziesz ich potrzebować zbyt często. +- Referencja to zwykły obiekt javascriptowy z pojedynczą właściwością o nazwie `current`, którą możesz odczytać lub ustawić. +- Możesz uzyskać referencję od Reacta, wywołując hook `useRef`. +- Podobnie jak stan, referencje pozwalają przechowywać informacje między ponownymi renderowaniami komponentu. +- W przeciwieństwie do stanu, ustawienie wartości `current` referencji nie powoduje ponownego renderowania. +- Nie odczytuj ani nie zapisuj `ref.current` podczas renderowania. To sprawia, że działanie komponentu staje się trudne do przewidzenia. </Recap> @@ -301,13 +301,13 @@ You can point a ref to any value. However, the most common use case for a ref is <Challenges> -#### Fix a broken chat input {/*fix-a-broken-chat-input*/} +#### Napraw uszkodzone pole wprowadzania czatu {/*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. +Wpisz wiadomość i kliknij "Wyślij". Zauważysz, że pojawi się opóźnienie trzech sekund, zanim zobaczysz komunikat "Wysłano!". W tym czasie możesz zobaczyć przycisk "Cofnij". Kliknij go. Przycisk "Cofnij" ma zatrzymać wyświetlanie komunikatu "Wysłano!". Robi to poprzez wywołanie metody [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) dla identyfikatora timeout zapisanego podczas `handleSend`. Jednak nawet po kliknięciu "Cofnij" komunikat "Wysłano!" nadal się pojawia. Znajdź przyczynę, dlaczego to nie działa i napraw to. <Hint> -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? +Zwykłe zmienne, takie jak `let timeoutID`, nie "przetrwają" między ponownymi renderowaniami, ponieważ każde renderowanie uruchamia twój komponent (i inicjalizuje jego zmienne) od nowa. Czy nie powinno się przechować identyfikatora timeoutu gdzie indziej? </Hint> @@ -324,7 +324,7 @@ export default function Chat() { function handleSend() { setIsSending(true); timeoutID = setTimeout(() => { - alert('Sent!'); + alert('Wysłano!'); setIsSending(false); }, 3000); } @@ -344,11 +344,11 @@ export default function Chat() { <button disabled={isSending} onClick={handleSend}> - {isSending ? 'Sending...' : 'Send'} + {isSending ? 'Wysyłanie...' : 'Wyślij'} </button> {isSending && <button onClick={handleUndo}> - Undo + Cofnij </button> } </> @@ -360,7 +360,7 @@ export default function Chat() { <Solution> -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. +Kiedy twój komponent jest renderowany ponownie (na przykład, gdy ustawisz stan), wszystkie zmienne lokalne są inicjalizowane od nowa. Dlatego nie możesz przechować identyfikatora timeoutu w zmiennej lokalnej, takiej jak `timeoutID` i oczekiwać, że inna funkcja obsługująca zdarzenie "zobaczy" ją w przyszłości. Zamiast tego, przechowaj go w referencji, którą React zachowa między renderowaniami. <Sandpack> @@ -375,7 +375,7 @@ export default function Chat() { function handleSend() { setIsSending(true); timeoutRef.current = setTimeout(() => { - alert('Sent!'); + alert('Wysłano!'); setIsSending(false); }, 3000); } @@ -395,11 +395,11 @@ export default function Chat() { <button disabled={isSending} onClick={handleSend}> - {isSending ? 'Sending...' : 'Send'} + {isSending ? 'Wysyłanie...' : 'Wyślij'} </button> {isSending && <button onClick={handleUndo}> - Undo + Cofnij </button> } </> @@ -412,9 +412,9 @@ export default function Chat() { </Solution> -#### Fix a component failing to re-render {/*fix-a-component-failing-to-re-render*/} +#### Napraw komponent, który nie renderuje się ponownie {/*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. +Ten przycisk powinien przełączać się między wyświetlaniem "Włącz" a "Wyłącz". Jednak zawsze wyświetla "Wyłącz". Co jest nie tak w tym kodzie? Napraw go. <Sandpack> @@ -428,7 +428,7 @@ export default function Toggle() { <button onClick={() => { isOnRef.current = !isOnRef.current; }}> - {isOnRef.current ? 'On' : 'Off'} + {isOnRef.current ? 'Włącz' : 'Wyłącz'} </button> ); } @@ -438,7 +438,7 @@ export default function Toggle() { <Solution> -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: +W tym przykładzie bieżąca wartość referencji jest używana do obliczenia wyniku renderowania: `{isOnRef.current ? 'Włącz' : 'Wyłącz'}`. Oznacza to, że ta informacja nie powinna być przechowywana w referencji, ale powinna zostać umieszczona w stanie. Aby to naprawić, należy usunąć referencję i zamiast niej użyć stanu: <Sandpack> @@ -452,7 +452,7 @@ export default function Toggle() { <button onClick={() => { setIsOn(!isOn); }}> - {isOn ? 'On' : 'Off'} + {isOn ? 'Włacz' : 'Wyłącz'} </button> ); } @@ -462,17 +462,17 @@ export default function Toggle() { </Solution> -#### Fix debouncing {/*fix-debouncing*/} +#### Napraw 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". +W tym przykładzie wszystkie procedury obsługi kliknięć przycisków są ["debouncowane".](https://redd.one/blog/debounce-vs-throttle) Aby zobaczyć, co to oznacza, naciśnij jeden z przycisków. Zauważ, że komunikat pojawi się sekundę później. Jeśli naciśniesz przycisk podczas oczekiwania na komunikat, licznik zostanie zresetowany. Dlatego, jeśli będziesz szybko klikać ten sam przycisk wiele razy, komunikat nie pojawi się, dopóki nie przestaniesz klikać przez sekundę. Debouncing pozwala opóźnić wykonanie jakiejś akcji, dopóki użytkownik "nie przestanie robić rzeczy". -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. +Ten przykład działa, ale nie do końca zgodnie z założeniami. Przyciski nie są niezależne. Aby zobaczyć problem, kliknij jeden z przycisków, a następnie natychmiast kliknij inny przycisk. Można się spodziewać, że po opóźnieniu pojawią się komunikaty obu przycisków. Pojawia się jednak tylko komunikat ostatniego przycisku. Wiadomość pierwszego przycisku zostaje utracona. -Why are the buttons interfering with each other? Find and fix the issue. +Dlaczego przyciski zakłócają się nawzajem? Znajdź problem i go rozwiąż. <Hint> -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? +Ostatnia zmienna identyfikatora timeoutu jest współdzielona pomiędzy wszystkimi komponentami `DebouncedButton`. Dlatego kliknięcie jednego przycisku resetuje timeout innego przycisku. Czy można przechowywać osobne identyfikatory timeoutu dla każdego przycisku? </Hint> @@ -498,19 +498,19 @@ export default function Dashboard() { return ( <> <DebouncedButton - onClick={() => alert('Spaceship launched!')} + onClick={() => alert('Statek kosmiczny wystartował!')} > - Launch the spaceship + Wystartuj statek kosmiczny </DebouncedButton> <DebouncedButton - onClick={() => alert('Soup boiled!')} + onClick={() => alert('Zupa się ugotowała!')} > - Boil the soup + Ugotuj zupę </DebouncedButton> <DebouncedButton - onClick={() => alert('Lullaby sung!')} + onClick={() => alert('Kołysanka zaśpiewana!')} > - Sing a lullaby + Zaśpiewaj kołysankę </DebouncedButton> </> ) @@ -525,7 +525,7 @@ button { display: block; margin: 10px; } <Solution> -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. +Zmienna taka jak `timeoutID` jest współdzielona między wszystkimi komponentami. Dlatego kliknięcie drugiego przycisku resetuje oczekujący timeout pierwszego przycisku. Aby to naprawić, można przechować timeout w referencji. Każdy przycisk będzie miał swoją własną referencję, dzięki czemu nie będą one ze sobą kolidować. Zauważ, że szybkie kliknięcie dwóch przycisków spowoduje wyświetlenie obu komunikatów. <Sandpack> @@ -550,19 +550,19 @@ export default function Dashboard() { return ( <> <DebouncedButton - onClick={() => alert('Spaceship launched!')} + onClick={() => alert('Statek kosmiczny wystartował!')} > - Launch the spaceship + Wystartuj statek kosmiczny </DebouncedButton> <DebouncedButton - onClick={() => alert('Soup boiled!')} + onClick={() => alert('Zupa się ugotowała!')} > - Boil the soup + Ugotuj zupę </DebouncedButton> <DebouncedButton - onClick={() => alert('Lullaby sung!')} + onClick={() => alert('Kołysanka zaśpiewana!')} > - Sing a lullaby + Zaśpiewaj kołysankę </DebouncedButton> </> ) @@ -577,11 +577,11 @@ button { display: block; margin: 10px; } </Solution> -#### Read the latest state {/*read-the-latest-state*/} +#### Odczytaj najnowszą wartość stanu {/*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). +W tym przykładzie, po naciśnięciu przycisku "Wyślij", występuje niewielkie opóźnienie przed wyświetleniem wiadomości. Wpisz "Cześć", naciśnij Wyślij, a następnie szybko edytuj dane wejściowe ponownie. Pomimo edycji, alert nadal będzie pokazywał "Cześć" (które było wartością stanu [w momencie](/learn/state-as-a-snapshot#state-over-time), kiedy przycisk został kliknięty). -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? +Zazwyczaj takie zachowanie jest pożądane w aplikacji. Mogą jednak wystąpić sporadyczne przypadki, w których chcesz, aby jakiś asynchroniczny kod odczytał *najnowszą* wersję jakiegoś stanu. Czy potrafisz wymyślić sposób, aby alert pokazywał *aktualny* tekst wprowadzony w polu, a nie ten, który był w momencie kliknięcia? <Sandpack> @@ -593,7 +593,7 @@ export default function Chat() { function handleSend() { setTimeout(() => { - alert('Sending: ' + text); + alert('Wysyłanie: ' + text); }, 3000); } @@ -605,7 +605,7 @@ export default function Chat() { /> <button onClick={handleSend}> - Send + Wyślij </button> </> ); @@ -616,7 +616,8 @@ export default function Chat() { <Solution> -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. +Stan działa [jak migawka](/learn/state-as-a-snapshot), więc nie można odczytać najnowszego stanu z operacji asynchronicznej, takiej jak np. timeout. Można jednak przechowywać najnowszy tekst wejściowy w referencji. Referencja jest mutowalna, więc można odczytać właściwość `current` w dowolnym momencie. Ponieważ bieżący tekst jest również używany do renderowania, w tym przykładzie będziesz potrzebować *zarówno* zmiennej stanu (do renderowania) *oraz* referencji (aby odczytać go w timeoucie). Trzeba będzie ręcznie zaktualizować bieżącą wartość referencji. + <Sandpack> @@ -634,7 +635,7 @@ export default function Chat() { function handleSend() { setTimeout(() => { - alert('Sending: ' + textRef.current); + alert('Wysyłanie: ' + textRef.current); }, 3000); } @@ -646,7 +647,7 @@ export default function Chat() { /> <button onClick={handleSend}> - Send + Wyślij </button> </> ); diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 3f0593599..74238163c 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -1,44 +1,44 @@ --- -title: Render and Commit +title: Renderowanie i aktualizowanie --- <Intro> -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. +Zanim twoje komponenty zostaną wyświetlone na ekranie, muszą zostać wyrenderowane przez Reacta. Zrozumienie tego procesu pomoże ci zrozumieć, jak wykonuje się twój kod i wyjaśni jego zachowanie. </Intro> <YouWillLearn> -* 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 +* Czym jest renderowanie w Reakcie +* Kiedy i dlaczego React renderuje komponenty +* Kroki związane z wyświetlaniem komponentów na ekranie +* Dlaczego renderowanie nie zawsze powoduje aktualizację drzewa DOM </YouWillLearn> -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: +Wyobraź sobie, że twoje komponenty to kucharze w kuchni, którzy przygotowują smaczne dania z dostępnych składników. W tej sytuacji React jest kelnerem, który przyjmuje zamówienia od klientów i przynosi im zamówione potrawy. Ten proces zgłaszania i obsługi interfejsu użytkownika składa się z trzech kroków: -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. **Wywołanie (ang. _triggering_)** renderowania (przekazanie zamówienia od gościa do kuchni) +2. **Renderowanie (ang. _rendering_)** komponentu (przygotowanie zamówienia w kuchni) +3. **Aktualizowanie (ang. _committing_)** drzewa DOM (umieszczenie zamówienia na stole) <IllustrationBlock sequential> - <Illustration caption="Trigger" alt="React as a server in a restaurant, fetching orders from the users and delivering them to the Component Kitchen." src="/images/docs/illustrations/i_render-and-commit1.png" /> - <Illustration caption="Render" alt="The Card Chef gives React a fresh Card component." src="/images/docs/illustrations/i_render-and-commit2.png" /> - <Illustration caption="Commit" alt="React delivers the Card to the user at their table." src="/images/docs/illustrations/i_render-and-commit3.png" /> + <Illustration caption="Wywołanie" alt="React jako kelner w restauracji, pobierający zamówienia od użytkowników i dostarczający je do Kuchni Komponentów." src="/images/docs/illustrations/i_render-and-commit1.png" /> + <Illustration caption="Renderowanie" alt="Kucharz komponentu Card przekazuje Reactowi świeży komponent Card." src="/images/docs/illustrations/i_render-and-commit2.png" /> + <Illustration caption="Aktualizowanie" alt="React dostarcza komponent Card użytkownikowi do jego stołu." src="/images/docs/illustrations/i_render-and-commit3.png" /> </IllustrationBlock> -## Step 1: Trigger a render {/*step-1-trigger-a-render*/} +## Krok 1: Wywołanie renderowania {/*step-1-trigger-a-render*/} -There are two reasons for a component to render: +Istnieją dwa powody, dla których komponent może zostać wyrenderowany: -1. It's the component's **initial render.** -2. The component's (or one of its ancestors') **state has been updated.** +1. To jest **początkowe renderowanie** komponentu. +2. Stan komponentu (lub jednego z jego rodziców) **został zaktualizowany**. -### Initial render {/*initial-render*/} +### Początkowe renderowanie {/*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: +Przy uruchamianiu swojej aplikacji, musisz wywołać początkowe renderowanie. Frameworki i piaskownice czasem ukrywają ten kod, ale jest on wywoływany poprzez wywołanie funkcji [`createRoot`](/reference/react-dom/client/createRoot) z docelowym węzłem drzewa DOM, a następnie wywołanie na nim metody `render` z twoim komponentem: <Sandpack> @@ -55,7 +55,7 @@ export default function Image() { return ( <img src="https://i.imgur.com/ZF6s192.jpg" - alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals" + alt="Rzeźba 'Floralis Genérica' wykonana przez Eduardo Catalano: ogromny metalowy kwiat z zwierciadlanymi płatkami" /> ); } @@ -63,28 +63,28 @@ export default function Image() { </Sandpack> -Try commenting out the `root.render()` call and see the component disappear! +Spróbuj zakomentować wywołanie `root.render()` i zauważ, że komponent znika! -### Re-renders when state updates {/*re-renders-when-state-updates*/} +### Przerenderowania po aktualizacji stanu {/*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.) +Po początkowym renderowaniu komponentu, możesz wywołać kolejne przerenderowania poprzez aktualizację jego stanu za pomocą [funkcji `set`](/reference/react/useState#setstate). Aktualizacja stanu komponentu automatycznie dodaje renderowanie do kolejki. (Możesz to sobie wyobrazić jako gościa restauracji zamawiającego herbatę, deser i wszelkiego rodzaju rzeczy już po złożeniu pierwszego zamówienia, w zależności od stanu jego pragnienia lub głodu.) <IllustrationBlock sequential> - <Illustration caption="State update..." alt="React as a server in a restaurant, serving a Card UI to the user, represented as a patron with a cursor for their head. They patron expresses they want a pink card, not a black one!" src="/images/docs/illustrations/i_rerender1.png" /> - <Illustration caption="...triggers..." alt="React returns to the Component Kitchen and tells the Card Chef they need a pink Card." src="/images/docs/illustrations/i_rerender2.png" /> - <Illustration caption="...render!" alt="The Card Chef gives React the pink Card." src="/images/docs/illustrations/i_rerender3.png" /> + <Illustration caption="Aktualizacja stanu..." alt="React jako kelner w restauracji, serwujący interfejs użytkownika Card użytkownikowi, przedstawionym jako klient z kursorem jako głową. Klient mówi, że chce komponent Card w kolorze różowym, a nie czarnym!" src="/images/docs/illustrations/i_rerender1.png" /> + <Illustration caption="...wywołuje..." alt="React wraca do Kuchni Komponentów i mówi Kucharzowi Komponentu Card, że potrzebuje komponent Card w kolorze różowym." src="/images/docs/illustrations/i_rerender2.png" /> + <Illustration caption="...renderowanie!" alt="Kucharz Komponentu Card dostarcza Reactowi komponent Card w kolorze różowym." src="/images/docs/illustrations/i_rerender3.png" /> </IllustrationBlock> -## Step 2: React renders your components {/*step-2-react-renders-your-components*/} +## Krok 2: React renderuje twoje komponenty {/*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.** +Po wywołaniu renderowania, React wywołuje twoje komponenty, aby ustalić, co wyświetlić na ekranie. **"Renderowanie" oznacza wywołanie twoich komponentów przez Reacta.** -* **On initial render,** React will call the root component. -* **For subsequent renders,** React will call the function component whose state update triggered the render. +* **Podczas początkowego renderowania,** React wywoła główny komponent. +* **Podczas kolejnych renderowań,** React wywoła funkcję komponentu, którego aktualizacja stanu wywołała renderowanie. -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. +Proces ten jest rekurencyjny: jeśli zaktualizowany komponent zwraca inny komponent, React następnie wyrenderuje _ten_ komponent, a jeśli ten komponent również coś zwraca, wyrenderuje _ten_ komponent, i tak dalej. Proces będzie kontynuowany, aż nie będzie więcej zagnieżdżonych komponentów i React będzie dokładnie wiedział, co powinno być wyświetlane na ekranie. -In the following example, React will call `Gallery()` and `Image()` several times: +W poniższym przykładzie React wywoła `Gallery()` i `Image()` kilkukrotnie: <Sandpack> @@ -92,7 +92,7 @@ In the following example, React will call `Gallery()` and `Image()` several tim export default function Gallery() { return ( <section> - <h1>Inspiring Sculptures</h1> + <h1>Inspirujące rzeźby</h1> <Image /> <Image /> <Image /> @@ -104,7 +104,7 @@ function Image() { return ( <img src="https://i.imgur.com/ZF6s192.jpg" - alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals" + alt="Rzeźba 'Floralis Genérica' wykonana przez Eduardo Catalano: ogromny metalowy kwiat z zwierciadlanymi płatkami" /> ); } @@ -124,36 +124,36 @@ img { margin: 0 10px 10px 0; } </Sandpack> -* **During the initial render,** React will [create the DOM nodes](https://developer.mozilla.org/docs/Web/API/Document/createElement) for `<section>`, `<h1>`, and three `<img>` 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. +* **Podczas początkowego renderowania,** React [utworzy węzły DOM](https://developer.mozilla.org/docs/Web/API/Document/createElement) dla znaczników `<section>`, `<h1>` i trzech znaczników `<img>`. +* **Podczas ponownego renderowania,** React obliczy, które z ich właściwości, jeśli jakiekolwiek, zostały zmienione od poprzedniego renderowania. Nic nie zrobi z tą informacją aż do następnego kroku, czyli fazy aktualizacji. <Pitfall> -Rendering must always be a [pure calculation](/learn/keeping-components-pure): +Renderowanie zawsze musi być [czystym obliczaniem](/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.) +* **Takie same wejścia, taki sam wynik.** Dla tych samych danych wejściowych, komponent powinien zawsze zwracać ten sam JSX - kiedy ktoś zamawia sałatkę z pomidorami, nie powinien otrzymać sałatki z cebulą! +* **Dbanie o swoje własne sprawy.** Komponent nie powinien zmieniać żadnych obiektów ani zmiennych, które już istniały przed renderowaniem - jedno zamówienie nie powinno móc zmieniać zamówienia kogoś innego. -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. +W przeciwnym razie możesz napotkać trudne do zrozumienia błędy i nieprzewidywalne zachowanie w miarę wzrostu złożoności kodu. Podczas pracy w "trybie rygorystycznym" (ang. _Strict Mode_) React wywołuje funkcję każdego komponentu dwa razy, co może pomóc w wykryciu błędów spowodowanych przez nieczyste funkcje. </Pitfall> <DeepDive> -#### Optimizing performance {/*optimizing-performance*/} +#### Optymalizacja wydajności {/*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!** +Domyślne zachowanie polegające na renderowaniu wszystkich komponentów zagnieżdżonych w zaktualizowanym komponencie nie jest optymalne pod względem wydajności, jeśli zaktualizowany komponent znajduje się bardzo wysoko w drzewie komponentów. Jeśli napotkasz problemy z wydajnością, istnieje kilka możliwych rozwiązań opisanych w sekcji [Wydajność](https://reactjs.org/docs/optimizing-performance.html). **Nie optymalizuj przedwcześnie!** </DeepDive> -## Step 3: React commits changes to the DOM {/*step-3-react-commits-changes-to-the-dom*/} +## Krok 3: React aktualizuje zmiany w drzewie DOM {/*step-3-react-commits-changes-to-the-dom*/} -After rendering (calling) your components, React will modify the DOM. +Po wyrenderowaniu (wywołaniu) twoich komponentów, React zmodyfikuje drzewo 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. +* **Podczas początkowego renderowania,** React użyje API drzewa DOM o nazwie [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild), aby umieścić na ekranie wszystkie węzły drzewa DOM, które utworzył. +* **Podczas przerenderowań,** React zastosuje minimum niezbędnych operacji (obliczonych podczas renderowania!), aby dopasować drzewo DOM do wyniku najnowszego renderowania. -**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 `<input>`, updating its `value`, but the text doesn't disappear when the component re-renders: +**React zmienia węzły drzewa DOM tylko wtedy, gdy występuje różnica pomiędzy renderowaniami.** Na przykład, oto komponent, który przerenderowuje się co sekundę z różnymi właściwościami przekazywanymi z jego rodzica. Zauważ, że możesz dodać tekst do elementu `<input>`, aktualizując jego atrybut `value`, ale tekst nie znika, gdy komponent renderuje się ponownie: <Sandpack> @@ -193,21 +193,21 @@ export default function App() { </Sandpack> -This works because during this last step, React only updates the content of `<h1>` with the new `time`. It sees that the `<input>` appears in the JSX in the same place as last time, so React doesn't touch the `<input>`—or its `value`! -## Epilogue: Browser paint {/*epilogue-browser-paint*/} +To działa, ponieważ podczas ostatniego kroku React aktualizuje tylko zawartość znacznika `<h1>` nową wartością `time`. Widzi on, że znacznik `<input>` pojawia się w JSXie w tym samym miejscu co ostatnim razem, więc React nie zmienia tego znacznika ani jego atrybutu `value`! +## Epilog: Malowanie przez przeglądarkę {/*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. +Po zakończeniu renderowania i zaktualizowaniu drzewa DOM przez Reacta, przeglądarka przemaluje ekran. Chociaż proces ten jest znany jako "renderowanie przez przeglądarkę", będziemy się odnosić do niego jako "malowanie", aby uniknąć nieporozumień w dokumentacji. -<Illustration alt="A browser painting 'still life with card element'." src="/images/docs/illustrations/i_browser-paint.png" /> +<Illustration alt="Przeglądarka malująca 'martwą naturę z elementem komponentu Card'." src="/images/docs/illustrations/i_browser-paint.png" /> <Recap> -* 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 +* Każda aktualizacja ekranu w aplikacji reactowej odbywa się w trzech krokach: + 1. Wywołanie + 2. Renderowanie + 3. Aktualizacja +* Możesz użyć trybu rygorystycznego, aby znaleźć błędy w swoich komponentach +* React nie modyfikuje drzewa DOM, jeśli wynik renderowania jest taki sam jak poprzednio </Recap> diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 108e394e2..a675b695d 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -1,74 +1,74 @@ --- -title: Rendering Lists +title: Renderowanie list --- <Intro> -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. +Często zdarzy ci się wyświetlać wiele podobnych komponentów na podstawie kolekcji danych. Możesz użyć [javascriptowych metod tablicowych](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array#), aby manipulować tablicą danych. Będziesz tu korzystać z [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) i [`map()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map) w połączeniu z Reactem, aby przefiltrować i przekształcić tablicę danych w tablicę komponentów. </Intro> <YouWillLearn> -* 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 +* Jak renderować komponenty z tablicy za pomocą javascriptowej funkcji `map()`. +* Jak renderować tylko konkretne komponenty za pomocą javascriptowej funkcji `filter()`. +* Kiedy i dlaczego stosować klucze (ang. _keys_) w Reakcie. </YouWillLearn> -## Rendering data from arrays {/*rendering-data-from-arrays*/} +## Renderowanie list z tablic {/*rendering-data-from-arrays*/} -Say that you have a list of content. +Załóżmy, że posiadasz pewną listę treści. ```js <ul> - <li>Creola Katherine Johnson: mathematician</li> - <li>Mario José Molina-Pasquel Henríquez: chemist</li> - <li>Mohammad Abdus Salam: physicist</li> - <li>Percy Lavon Julian: chemist</li> - <li>Subrahmanyan Chandrasekhar: astrophysicist</li> + <li>Creola Katherine Johnson: matematyczka</li> + <li>Mario José Molina-Pasquel Henríquez: chemik</li> + <li>Mohammad Abdus Salam: fizyk</li> + <li>Percy Lavon Julian: chemik</li> + <li>Subrahmanyan Chandrasekhar: astrofizyk</li> </ul> ``` -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. +Jedyna różnica między elementami tej listy to ich treść, ich dane. Często będziesz chcieć pokazać kilka instancji tego samego komponentu, używając różnych danych podczas tworzenia interfejsów: od list komentarzy do galerii obrazków profilowych. W takich sytuacjach możesz przechowywać te dane w obiektach i tablicach javascriptowych oraz używać metod, takich jak [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) i [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), aby renderować na ich podstawie listy komponentów. -Here’s a short example of how to generate a list of items from an array: +Oto krótki przykład, jak generować listę elementów z tablicy: -1. **Move** the data into an array: +1. **Przenieś** dane do tablicy: ```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: matematyczka', + 'Mario José Molina-Pasquel Henríquez: chemik', + 'Mohammad Abdus Salam: fizyk', + 'Percy Lavon Julian: chemik', + 'Subrahmanyan Chandrasekhar: astrofizyk' ]; ``` -2. **Map** the `people` members into a new array of JSX nodes, `listItems`: +2. **Zmapuj** elementy tablicy `people` na nową tablicę węzłów JSX, `listItems`: ```js const listItems = people.map(person => <li>{person}</li>); ``` -3. **Return** `listItems` from your component wrapped in a `<ul>`: +3. **Zwróć** tablicę `listItems` z twojego komponentu, opakowaną w element `<ul>`: ```js return <ul>{listItems}</ul>; ``` -Here is the result: +Oto rezultat: <Sandpack> ```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: matematyczka', + 'Mario José Molina-Pasquel Henríquez: chemik', + 'Mohammad Abdus Salam: fizyk', + 'Percy Lavon Julian: chemik', + 'Subrahmanyan Chandrasekhar: astrofizyk' ]; export default function List() { @@ -85,7 +85,7 @@ li { margin-bottom: 10px; } </Sandpack> -Notice the sandbox above displays a console error: +Zauważ, że powyższy sandbox wyświetla błąd w konsoli: <ConsoleBlock level="error"> @@ -93,47 +93,49 @@ Warning: Each child in a list should have a unique "key" prop. </ConsoleBlock> -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. +Poniżej na tej stronie dowiesz się, jak naprawić ten błąd. Zanim do tego przejdziemy, nadajmy trochę struktury twoim danym. -## Filtering arrays of items {/*filtering-arrays-of-items*/} +## Filtrowanie tablicy elementów {/*filtering-arrays-of-items*/} -This data can be structured even more. +Dane te można jeszcze bardziej ustrukturyzować. ```js const people = [{ id: 0, name: 'Creola Katherine Johnson', - profession: 'mathematician', + profession: 'matematyczka', }, { id: 1, name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', + profession: 'chemik', }, { id: 2, name: 'Mohammad Abdus Salam', - profession: 'physicist', + profession: 'fizyk', }, { + id: 3, name: 'Percy Lavon Julian', - profession: 'chemist', + profession: 'chemik', }, { + id: 4, name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', + profession: 'astrofizyk', }]; ``` -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`). +Załóżmy, że chcesz mieć możliwość pokazywania tylko tych osób, których zawód to `'chemik'`. Możesz skorzystać z javascriptowej metody `filter()`, aby zwrócić tylko takie osoby. Metoda ta przyjmuje tablicę, poddaje jej elementy "testowi" (funkcji, która zwraca `true` lub `false`) i zwraca nową tablicę tylko tych elementów, które zdały test (zwróciły `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: +Chcąc uzyskać tylko te elementy, gdzie `profession` jest ustawione na `'chemik'`, odpowiednia funkcja "testu" powinna wyglądać tak: `(person) => person.profession === 'chemik'`. Oto sposób na to, jak to wszystko połączyć w całość: -1. **Create** a new array of just “chemist” people, `chemists`, by calling `filter()` on the `people` filtering by `person.profession === 'chemist'`: +1. **Utwórz** nową tablicę zawierającą tylko osoby o zawodzie `'chemik'` i nazwij ją `chemists`. Wywołaj metodę `filter()` na tablicy `people`, filtrując według warunku `person.profession === 'chemik'` i przypisz jej rezultat do nowo utworzonej tablicy: ```js const chemists = people.filter(person => - person.profession === 'chemist' + person.profession === 'chemik' ); ``` -2. Now **map** over `chemists`: +2. Teraz **zmapuj** tablicę `chemists`: ```js {1,13} const listItems = chemists.map(person => @@ -145,13 +147,13 @@ const listItems = chemists.map(person => <p> <b>{person.name}:</b> {' ' + person.profession + ' '} - known for {person.accomplishment} + {person.accomplishment}. </p> </li> ); ``` -3. Lastly, **return** the `listItems` from your component: +3. Wreszcie **zwróć** `listItems` z twojego komponentu: ```js return <ul>{listItems}</ul>; @@ -165,7 +167,7 @@ import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => - person.profession === 'chemist' + person.profession === 'chemik' ); const listItems = chemists.map(person => <li> @@ -176,7 +178,7 @@ export default function List() { <p> <b>{person.name}:</b> {' ' + person.profession + ' '} - known for {person.accomplishment} + {person.accomplishment}. </p> </li> ); @@ -188,32 +190,32 @@ export default function List() { export const people = [{ id: 0, name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + profession: 'matematyczka', + accomplishment: 'znana z obliczeń związanych z lotami kosmicznymi', imageId: 'MK3eW3A' }, { id: 1, name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + profession: 'chemik', + accomplishment: 'znany z odkrycia dziury ozonowej nad Arktyką', imageId: 'mynHUSa' }, { id: 2, name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + profession: 'fizyk', + accomplishment: 'znany z prac nad teorią elektromagnetyzmu', imageId: 'bE7W1ji' }, { id: 3, name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + profession: 'chemik', + accomplishment: 'znany z pionierskich prac nad lekami na bazie kortyzonu, steroidami i pigułkami antykoncepcyjnymi', imageId: 'IOjWm71' }, { id: 4, name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + profession: 'astrofizyk', + accomplishment: 'znany z obliczeń masy białych karłów', imageId: 'lrWQx8l' }]; ``` @@ -244,29 +246,29 @@ img { width: 100px; height: 100px; border-radius: 50%; } <Pitfall> -Arrow functions implicitly return the expression right after `=>`, so you didn't need a `return` statement: +Funkcje strzałkowe (ang. _arrow function_) niejawnie zwracają wyrażenie znajdujące się zaraz po `=>`, więc nie musisz używać instrukcji `return`: ```js const listItems = chemists.map(person => - <li>...</li> // Implicit return! + <li>...</li> // Niejawne zwrócenie! ); ``` -However, **you must write `return` explicitly if your `=>` is followed by a `{` curly brace!** +Natomiast **musisz wprost napisać `return`, jeśli po twoim `=>` znajduje się nawias klamrowy!** ```js -const listItems = chemists.map(person => { // Curly brace +const listItems = chemists.map(person => { // Nawias klamrowy return <li>...</li>; }); ``` -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! +Funkcje strzałkowe zawierające `=> {` są określane jako posiadające ["ciało blokowe"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#function_body). Pozwalają one na napisanie więcej niż jednej linii kodu, ale *zawsze musisz* samodzielnie napisać instrukcję `return`. Jeśli to przeoczysz, nic nie zostanie zwrócone! </Pitfall> -## Keeping list items in order with `key` {/*keeping-list-items-in-order-with-key*/} +## Zachowanie kolejności elementów listy za pomocą `key` (ang. _klucz_) {/*keeping-list-items-in-order-with-key*/} -Notice that all the sandboxes above show an error in the console: +Zauważ, że wszystkie powyższe sandboxy wyświetlają błąd w konsoli: <ConsoleBlock level="error"> @@ -274,7 +276,7 @@ Warning: Each child in a list should have a unique "key" prop. </ConsoleBlock> -You need to give each array item a `key` -- a string or a number that uniquely identifies it among other items in that array: +Każdemu elementowi tablicy musisz przypisać klucz `key`, czyli łańcuch znaków lub liczbę, która jednoznacznie identyfikuje go wśród innych elementów w tej tablicy: ```js <li key={person.id}>...</li> @@ -282,13 +284,13 @@ You need to give each array item a `key` -- a string or a number that uniquely i <Note> -JSX elements directly inside a `map()` call always need keys! +Elementy JSX bezpośrednio wewnątrz wywołania funkcji `map()` muszą zawsze mieć przypisane klucze! </Note> -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. +Klucze `key` pozwalają Reactowi zrozumieć, który komponent odpowiada któremu elementowi tablicy, dzięki czemu może je później dopasować. Jest to istotne, jeśli elementy tablicy mogą być przemieszczane (np. w wyniku sortowania), dodawane lub usuwane. Dobrze dobrany klucz `key` pomaga Reactowi wywnioskować, co dokładnie się stało, i dokonać odpowiednich aktualizacji drzewa DOM. -Rather than generating keys on the fly, you should include them in your data: +Zamiast generować klucze dynamicznie, powinno się dołączać je do danych: <Sandpack> @@ -306,7 +308,7 @@ export default function List() { <p> <b>{person.name}</b> {' ' + person.profession + ' '} - known for {person.accomplishment} + {person.accomplishment}. </p> </li> ); @@ -316,34 +318,34 @@ export default function List() { ```js src/data.js active export const people = [{ - id: 0, // Used in JSX as a key + id: 0, // Użyte w JSX jako klucz name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + profession: 'matematyczka', + accomplishment: 'znana z obliczeń związanych z lotami kosmicznymi', imageId: 'MK3eW3A' }, { - id: 1, // Used in JSX as a key + id: 1, // Użyte w JSX jako klucz name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + profession: 'chemik', + accomplishment: 'znany z odkrycia dziury ozonowej nad Arktyką', imageId: 'mynHUSa' }, { - id: 2, // Used in JSX as a key + id: 2, // Użyte w JSX jako klucz name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + profession: 'fizyk', + accomplishment: 'znany z prac nad teorią elektromagnetyzmu', imageId: 'bE7W1ji' }, { - id: 3, // Used in JSX as a key + id: 3, // Użyte w JSX jako klucz name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + profession: 'chemik', + accomplishment: 'znany z pionierskich prac nad lekami na bazie kortyzonu, steroidami i pigułkami antykoncepcyjnymi', imageId: 'IOjWm71' }, { - id: 4, // Used in JSX as a key + id: 4, // Użyte w JSX jako klucz name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + profession: 'astrofizyk', + accomplishment: 'znany z obliczeń masy białych karłów', imageId: 'lrWQx8l' }]; ``` @@ -374,11 +376,11 @@ img { width: 100px; height: 100px; border-radius: 50%; } <DeepDive> -#### Displaying several DOM nodes for each list item {/*displaying-several-dom-nodes-for-each-list-item*/} +#### Wyświetlanie kilku węzłów drzewa DOM dla każdego elementu listy {/*displaying-several-dom-nodes-for-each-list-item*/} -What do you do when each item needs to render not one, but several DOM nodes? +Co zrobić, gdy każdy element musi renderować nie jeden, ale kilka węzłów drzewa 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 `<div>`, or use the slightly longer and [more explicit `<Fragment>` syntax:](/reference/react/Fragment#rendering-a-list-of-fragments) +Krótka składnia [`<>...</>` Fragment](/reference/react/Fragment) nie pozwala na przekazanie klucza, więc musisz albo zgrupować je w pojedynczy `<div>`, albo użyć nieco dłuższej i [bardziej jawnej składni `<Fragment>`:](/reference/react/Fragment#rendering-a-list-of-fragments) ```js import { Fragment } from 'react'; @@ -393,46 +395,45 @@ const listItems = people.map(person => ); ``` -Fragments disappear from the DOM, so this will produce a flat list of `<h1>`, `<p>`, `<h1>`, `<p>`, and so on. +Fragmenty nie pojawiają się w drzewie DOM, więc użycie ich spowoduje uzyskanie płaskiej listy elementów `<h1>`, `<p>`, `<h1>`, `<p>` i tak dalej. </DeepDive> -### Where to get your `key` {/*where-to-get-your-key*/} - -Different sources of data provide different sources of keys: +### Skąd wziąć klucze `key` {/*where-to-get-your-key*/} -* **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. +Różne źródła danych dostarczają różnych kluczy: -### Rules of keys {/*rules-of-keys*/} +* **Dane z bazy danych:** Jeśli twoje dane pochodzą z bazy danych, możesz używać kluczy lub ID z tej bazy danych, które z natury są unikalne. +* **Lokalnie generowane dane:** Jeśli twoje dane są generowane i przechowywane lokalnie (np. notatki w aplikacji do robienia notatek), użyj licznika przyrostowego [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) lub paczki takiej jak [`uuid`](https://www.npmjs.com/package/uuid) podczas tworzenia elementów. +### Zasady kluczy {/*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. +* **Klucze muszą być unikalne między rodzeństwem.** Jednakże używanie tych samych kluczy dla węzłów JSX w _różnych_ tablicach jest jak najbardziej w porządku. +* **Klucze nie mogą się zmieniać,** bo to przeczy ich celowi! Nie generuj ich podczas renderowania. -### Why does React need keys? {/*why-does-react-need-keys*/} +### Dlaczego React potrzebuje kluczy? {/*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. +Wyobraź sobie, że pliki na twoim pulpicie nie mają nazw. Zamiast tego trzeba odwoływać się do nich przez ich kolejność - pierwszy plik, drugi plik i tak dalej. Można się do tego przyzwyczaić, ale gdyby usunąć plik, zaczęłoby być to kłopotliwe. Drugi plik stałby się pierwszym plikiem, trzeci plik byłby drugim plikiem i tak dalej. -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. +Nazwy plików w folderze i klucze JSX w tablicy pełnią podobną rolę. Pozwalają nam jednoznacznie identyfikować element pośród swojego rodzeństwa. Dobrze dobrany klucz dostarcza więcej informacji niż pozycja w tablicy. Nawet jeśli _pozycja_ zmieni się ze względu na ponowne sortowanie, klucz pozwala Reactowi identyfikować element przez cały cykl jego życia. <Pitfall> -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. +Możesz skusić się, aby użyć indeksu elementu w tablicy jako jego klucza. W rzeczywistości to właśnie jego użyje React, jeśli w ogóle nie określisz klucza. Jednak kolejność renderowania elementów będzie się zmieniać w miarę czasu, gdy jakiś element zostanie dodany, usunięty lub jeśli tablica zostanie posortowana. Indeks jako klucz często prowadzi do mało oczywistych i mylących błędów. -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. +Podobnie nie generuj kluczy dynamicznie, na przykład za pomocą `key={Math.random()}`. Spowoduje to, że klucze nigdy nie będą się zgadzać między renderowaniami, co poskutkuje za każdym razem tworzeniem od nowa wszystkich komponentów i drzewa DOM. Nie tylko będzie to wolne, ale również sprawi, że utracisz wszystkie dane wprowadzone przez użytkownika wewnątrz elementów listy. Zamiast tego użyj stałego identyfikatora opartego na danych. -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: `<Profile key={id} userId={id} />`. +Zauważ, że twoje komponenty nie otrzymają `key` przez właściwości. Jest on używany jedynie jako wskazówka dla samego Reacta. Jeśli twój komponent potrzebuje identyfikatora, musisz przekazać go jako oddzielną właściwość: `<Profile key={id} userId={id} />`. </Pitfall> <Recap> -On this page you learned: +Na tej stronie nauczyliśmy cię: -* 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. +* Jak przenieść dane z komponentów do struktur danych, takich jak tablice i obiekty. +* Jak generować zbiory podobnych komponentów za pomocą javascriptowej funkcji `map()`. +* Jak tworzyć tablice przefiltrowanych elementów za pomocą javascriptowej funkcji `filter()`. +* Jak i dlaczego ustawiać klucz `key` dla każdego komponentu w kolekcji, aby React mógł śledzić każdy z nich, nawet jeśli zmienią się ich pozycja lub dane. </Recap> @@ -440,11 +441,11 @@ On this page you learned: <Challenges> -#### Splitting a list in two {/*splitting-a-list-in-two*/} +#### Dzielenie listy na dwie {/*splitting-a-list-in-two*/} -This example shows a list of all people. +Ten przykład wyświetla listę wszystkich osób. -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'`. +Zmień go tak, aby pokazywał dwie oddzielne listy jedna po drugiej: **Chemia** i **Wszyscy Inni.** Tak jak wcześniej, możesz określić, czy osoba jest związana z chemią, sprawdzając warunek `person.profession === 'chemist'`. <Sandpack> @@ -462,13 +463,13 @@ export default function List() { <p> <b>{person.name}:</b> {' ' + person.profession + ' '} - known for {person.accomplishment} + {person.accomplishment}. </p> </li> ); return ( <article> - <h1>Scientists</h1> + <h1>Naukowcy</h1> <ul>{listItems}</ul> </article> ); @@ -479,32 +480,32 @@ export default function List() { export const people = [{ id: 0, name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + profession: 'matematyczka', + accomplishment: 'znana z obliczeń związanych z lotami kosmicznymi', imageId: 'MK3eW3A' }, { id: 1, name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + profession: 'chemik', + accomplishment: 'znany z odkrycia dziury ozonowej nad Arktyką', imageId: 'mynHUSa' }, { id: 2, name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + profession: 'fizyk', + accomplishment: 'znany z prac nad teorią elektromagnetyzmu', imageId: 'bE7W1ji' }, { id: 3, name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + profession: 'chemik', + accomplishment: 'znany z pionierskich prac nad lekami na bazie kortyzonu, steroidami i pigułkami antykoncepcyjnymi', imageId: 'IOjWm71' }, { id: 4, name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + profession: 'astrofizyk', + accomplishment: 'znany z obliczeń masy białych karłów', imageId: 'lrWQx8l' }]; ``` @@ -535,7 +536,7 @@ img { width: 100px; height: 100px; border-radius: 50%; } <Solution> -You could use `filter()` twice, creating two separate arrays, and then `map` over both of them: +Możesz użyć funkcji `filter()` dwukrotnie, tworząc dwie osobne tablice, a następnie użyć funkcji `map()` dla obu z nich: <Sandpack> @@ -545,15 +546,15 @@ import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => - person.profession === 'chemist' + person.profession === 'chemik' ); const everyoneElse = people.filter(person => - person.profession !== 'chemist' + person.profession !== 'chemik' ); return ( <article> - <h1>Scientists</h1> - <h2>Chemists</h2> + <h1>Naukowcy</h1> + <h2>Chemicy</h2> <ul> {chemists.map(person => <li key={person.id}> @@ -564,12 +565,12 @@ export default function List() { <p> <b>{person.name}:</b> {' ' + person.profession + ' '} - known for {person.accomplishment} + {person.accomplishment}. </p> </li> )} </ul> - <h2>Everyone Else</h2> + <h2>Wszyscy inni</h2> <ul> {everyoneElse.map(person => <li key={person.id}> @@ -580,7 +581,7 @@ export default function List() { <p> <b>{person.name}:</b> {' ' + person.profession + ' '} - known for {person.accomplishment} + {person.accomplishment}. </p> </li> )} @@ -594,32 +595,32 @@ export default function List() { export const people = [{ id: 0, name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + profession: 'matematyczka', + accomplishment: 'znana z obliczeń związanych z lotami kosmicznymi', imageId: 'MK3eW3A' }, { id: 1, name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + profession: 'chemik', + accomplishment: 'znany z odkrycia dziury ozonowej nad Arktyką', imageId: 'mynHUSa' }, { id: 2, name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + profession: 'fizyk', + accomplishment: 'znany z prac nad teorią elektromagnetyzmu', imageId: 'bE7W1ji' }, { id: 3, name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + profession: 'chemik', + accomplishment: 'znany z pionierskich prac nad lekami na bazie kortyzonu, steroidami i pigułkami antykoncepcyjnymi', imageId: 'IOjWm71' }, { id: 4, name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + profession: 'astrofizyk', + accomplishment: 'znany z obliczeń masy białych karłów', imageId: 'lrWQx8l' }]; ``` @@ -648,9 +649,9 @@ img { width: 100px; height: 100px; border-radius: 50%; } </Sandpack> -In this solution, the `map` calls are placed directly inline into the parent `<ul>` elements, but you could introduce variables for them if you find that more readable. +W rozwiązaniu tym, wywołania funkcji `map()` są umieszczone bezpośrednio wewnątrz elementów nadrzędnych `<ul>`, ale możesz przenieść je do zmiennych, aby zwiększyć czytelność. -There is still a bit duplication between the rendered lists. You can go further and extract the repetitive parts into a `<ListSection>` component: +Nadal zachodzi tu duplikacja kodu między listami. Możesz pójść dalej i wyodrębnić jego powtarzające się części do komponentu `<ListSection>`: <Sandpack> @@ -672,7 +673,7 @@ function ListSection({ title, people }) { <p> <b>{person.name}:</b> {' ' + person.profession + ' '} - known for {person.accomplishment} + {person.accomplishment}. </p> </li> )} @@ -683,20 +684,20 @@ function ListSection({ title, people }) { export default function List() { const chemists = people.filter(person => - person.profession === 'chemist' + person.profession === 'chemik' ); const everyoneElse = people.filter(person => - person.profession !== 'chemist' + person.profession !== 'chemik' ); return ( <article> - <h1>Scientists</h1> + <h1>Naukowcy</h1> <ListSection - title="Chemists" + title="Chemicy" people={chemists} /> <ListSection - title="Everyone Else" + title="Wszyscy inni" people={everyoneElse} /> </article> @@ -708,32 +709,32 @@ export default function List() { export const people = [{ id: 0, name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + profession: 'matematyczka', + accomplishment: 'znana z obliczeń związanych z lotami kosmicznymi', imageId: 'MK3eW3A' }, { id: 1, name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + profession: 'chemik', + accomplishment: 'znany z odkrycia dziury ozonowej nad Arktyką', imageId: 'mynHUSa' }, { id: 2, name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + profession: 'fizyk', + accomplishment: 'znany z prac nad teorią elektromagnetyzmu', imageId: 'bE7W1ji' }, { id: 3, name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + profession: 'chemik', + accomplishment: 'znany z pionierskich prac nad lekami na bazie kortyzonu, steroidami i pigułkami antykoncepcyjnymi', imageId: 'IOjWm71' }, { id: 4, name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + profession: 'astrofizyk', + accomplishment: 'znany z obliczeń masy białych karłów', imageId: 'lrWQx8l' }]; ``` @@ -762,9 +763,9 @@ img { width: 100px; height: 100px; border-radius: 50%; } </Sandpack> -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. +Bardzo uważny czytelnik może zauważyć, że przy dwóch wywołaniach funkcji `filter()`, zawód każdej osoby jest sprawdzany dwukrotnie. W tym przykładzie, sprawdzanie właściwości jest bardzo szybkie, więc jest to akceptowalne rozwiązanie. Jeśli jednak twoja logika byłaby bardziej kosztowna, można by zastąpić wywołania funkcji `filter()` pętlą, która ręcznie konstruuje tablice i sprawdza każdą osobę tylko raz. -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: +W zasadzie, jeśli tablica `people` nigdy się nie zmienia, możesz przenieść ten kod poza komponent. Z punktu widzenia Reacta, ważne jest tylko to, aby ostatecznie dostarczyć mu tablicę węzłów JSX. Nie ma to znaczenia, w jaki sposób generujesz tę tablicę: <Sandpack> @@ -775,7 +776,7 @@ import { getImageUrl } from './utils.js'; let chemists = []; let everyoneElse = []; people.forEach(person => { - if (person.profession === 'chemist') { + if (person.profession === 'chemik') { chemists.push(person); } else { everyoneElse.push(person); @@ -796,7 +797,7 @@ function ListSection({ title, people }) { <p> <b>{person.name}:</b> {' ' + person.profession + ' '} - known for {person.accomplishment} + {person.accomplishment}. </p> </li> )} @@ -808,13 +809,13 @@ function ListSection({ title, people }) { export default function List() { return ( <article> - <h1>Scientists</h1> + <h1>Naukowcy</h1> <ListSection - title="Chemists" + title="Chemicy" people={chemists} /> <ListSection - title="Everyone Else" + title="Wszyscy inni" people={everyoneElse} /> </article> @@ -826,32 +827,32 @@ export default function List() { export const people = [{ id: 0, name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + profession: 'matematyczka', + accomplishment: 'znana z obliczeń związanych z lotami kosmicznymi', imageId: 'MK3eW3A' }, { id: 1, name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + profession: 'chemik', + accomplishment: 'znany z odkrycia dziury ozonowej nad Arktyką', imageId: 'mynHUSa' }, { id: 2, name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + profession: 'fizyk', + accomplishment: 'znany z prac nad teorią elektromagnetyzmu', imageId: 'bE7W1ji' }, { id: 3, name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + profession: 'chemik', + accomplishment: 'znany z pionierskich prac nad lekami na bazie kortyzonu, steroidami i pigułkami antykoncepcyjnymi', imageId: 'IOjWm71' }, { id: 4, name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + profession: 'astrofizyk', + accomplishment: 'znany z obliczeń masy białych karłów', imageId: 'lrWQx8l' }]; ``` @@ -882,13 +883,13 @@ img { width: 100px; height: 100px; border-radius: 50%; } </Solution> -#### Nested lists in one component {/*nested-lists-in-one-component*/} +#### Listy zagnieżdżone w jednym komponencie {/*nested-lists-in-one-component*/} -Make a list of recipes from this array! For each recipe in the array, display its name as an `<h2>` and list its ingredients in a `<ul>`. +Stwórz listę przepisów z tej tablicy! Dla każdego przepisu z tablicy wyświetl jego nazwę jako `<h2>` i wypisz składniki w `<ul>`. <Hint> -This will require nesting two different `map` calls. +Będzie to wymagało zagnieżdżenia dwóch różnych wywołań funkcji `map()`. </Hint> @@ -900,7 +901,7 @@ import { recipes } from './data.js'; export default function RecipeList() { return ( <div> - <h1>Recipes</h1> + <h1>Przepisy</h1> </div> ); } @@ -909,16 +910,16 @@ export default function RecipeList() { ```js src/data.js export const recipes = [{ id: 'greek-salad', - name: 'Greek Salad', - ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta'] + name: 'Sałatka grecka', + ingredients: ['pomidory', 'ogórek', 'cebula', 'oliwki', 'feta'] }, { id: 'hawaiian-pizza', - name: 'Hawaiian Pizza', - ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple'] + name: 'Pizza hawajska', + ingredients: ['ciasto na pizze', 'sos do pizzy', 'mozzarella', 'szynka', 'ananas'] }, { id: 'hummus', - name: 'Hummus', - ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini'] + name: 'Humus', + ingredients: ['ciecierzyca', 'oliwa z oliwek', 'ząbki czosnku', 'cytryna', 'tahini'] }]; ``` @@ -926,7 +927,7 @@ export const recipes = [{ <Solution> -Here is one way you could go about it: +Oto jedna z możliwości, jak można to zrealizować: <Sandpack> @@ -936,7 +937,7 @@ import { recipes } from './data.js'; export default function RecipeList() { return ( <div> - <h1>Recipes</h1> + <h1>Przepisy</h1> {recipes.map(recipe => <div key={recipe.id}> <h2>{recipe.name}</h2> @@ -957,28 +958,28 @@ export default function RecipeList() { ```js src/data.js export const recipes = [{ id: 'greek-salad', - name: 'Greek Salad', - ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta'] + name: 'Sałatka grecka', + ingredients: ['pomidory', 'ogórek', 'cebula', 'oliwki', 'feta'] }, { id: 'hawaiian-pizza', - name: 'Hawaiian Pizza', - ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple'] + name: 'Pizza hawajska', + ingredients: ['ciasto na pizze', 'sos do pizzy', 'mozzarella', 'szynka', 'ananas'] }, { id: 'hummus', - name: 'Hummus', - ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini'] + name: 'Humus', + ingredients: ['ciecierzyca', 'oliwa z oliwek', 'ząbki czosnku', 'cytryna', 'tahini'] }]; ``` </Sandpack> -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). +Każdy z przepisów zawiera już pole `id`, więc właśnie to pole jest używane jako `key` w zewnętrznej pętli. Brak jest jednak identyfikatora, którego można by użyć do iteracji po składnikach. Niemniej jednak, można założyć, że ten sam składnik nie będzie wymieniony dwukrotnie w ramach tego samego przepisu, więc jego nazwa może posłużyć jako `key`. Ewentualnie, można by zmienić strukturę danych, dodając identyfikatory lub użyć indeksu jako `key` (z zastrzeżeniem, że nie można bezpiecznie zmieniać kolejności składników). </Solution> -#### Extracting a list item component {/*extracting-a-list-item-component*/} +#### Wyodrębnianie komponentu elementu listy {/*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? +Komponent `RecipeList` zawiera dwa zagnieżdżone wywołania funkcji `map()`. Aby to uprościć, wyodrębnij komponent `Recipe`, który będzie przyjmować właściwości `id`, `name` oraz `ingredients`. Gdzie umieścisz zewnętrzny klucz `key` i dlaczego? <Sandpack> @@ -988,7 +989,7 @@ import { recipes } from './data.js'; export default function RecipeList() { return ( <div> - <h1>Recipes</h1> + <h1>Przepisy</h1> {recipes.map(recipe => <div key={recipe.id}> <h2>{recipe.name}</h2> @@ -1009,16 +1010,16 @@ export default function RecipeList() { ```js src/data.js export const recipes = [{ id: 'greek-salad', - name: 'Greek Salad', - ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta'] + name: 'Sałatka grecka', + ingredients: ['pomidory', 'ogórek', 'cebula', 'oliwki', 'feta'] }, { id: 'hawaiian-pizza', - name: 'Hawaiian Pizza', - ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple'] + name: 'Pizza hawajska', + ingredients: ['ciasto na pizze', 'sos do pizzy', 'mozzarella', 'szynka', 'ananas'] }, { id: 'hummus', - name: 'Hummus', - ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini'] + name: 'Humus', + ingredients: ['ciecierzyca', 'oliwa z oliwek', 'ząbki czosnku', 'cytryna', 'tahini'] }]; ``` @@ -1026,7 +1027,7 @@ export const recipes = [{ <Solution> -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`: +Możesz przenieść JSX z zewnętrznego wywołania funkcji `map()` do nowego komponentu `Recipe` i zwrócić ten JSX. Następnie możesz zmienić `recipe.name` na `name`, `recipe.id` na `id` itd., a następnie przekazać je jako właściwości do komponentu `Recipe`: <Sandpack> @@ -1051,7 +1052,7 @@ function Recipe({ id, name, ingredients }) { export default function RecipeList() { return ( <div> - <h1>Recipes</h1> + <h1>Przepisy</h1> {recipes.map(recipe => <Recipe {...recipe} key={recipe.id} /> )} @@ -1063,51 +1064,51 @@ export default function RecipeList() { ```js src/data.js export const recipes = [{ id: 'greek-salad', - name: 'Greek Salad', - ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta'] + name: 'Sałatka grecka', + ingredients: ['pomidory', 'ogórek', 'cebula', 'oliwki', 'feta'] }, { id: 'hawaiian-pizza', - name: 'Hawaiian Pizza', - ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple'] + name: 'Pizza hawajska', + ingredients: ['ciasto na pizze', 'sos do pizzy', 'mozzarella', 'szynka', 'ananas'] }, { id: 'hummus', - name: 'Hummus', - ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini'] + name: 'Humus', + ingredients: ['ciecierzyca', 'oliwa z oliwek', 'ząbki czosnku', 'cytryna', 'tahini'] }]; ``` </Sandpack> -Here, `<Recipe {...recipe} key={recipe.id} />` 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 id={recipe.id} name={recipe.name} ingredients={recipe.ingredients} key={recipe.id} />`. +Użyta tutaj składnia `<Recipe {...recipe} key={recipe.id} />` to skrócony zapis, mówiący "przekaż wszystkie właściwości obiektu `recipe` jako właściwości do komponentu `Recipe`". Możesz także przekazać każdą właściwość jawnie: `<Recipe id={recipe.id} name={recipe.name} ingredients={recipe.ingredients} key={recipe.id} />`. -**Note that the `key` is specified on the `<Recipe>` itself rather than on the root `<div>` returned from `Recipe`.** This is because this `key` is needed directly within the context of the surrounding array. Previously, you had an array of `<div>`s so each of them needed a `key`, but now you have an array of `<Recipe>`s. In other words, when you extract a component, don't forget to leave the `key` outside the JSX you copy and paste. +**Zauważ, że klucz `key` jest określony bezpośrednio dla `<Recipe>`, a nie dla najwyższego elementu `<div>`, który jest zwracany przez `Recipe`.** To dlatego, że `key` jest potrzebny bezpośrednio w kontekście otaczającej tablicy. Wcześniej mieliśmy tablicę elementów `<div>`, więc każdy z nich potrzebował `key`, ale teraz mamy tablicę komponentów `<Recipe>`. Innymi słowy, podczas wyodrębniania komponentu, nie zapomnij umieścić `key` poza kodem JSX, który przenosisz. </Solution> -#### List with a separator {/*list-with-a-separator*/} +#### Lista z separatorem {/*list-with-a-separator*/} -This example renders a famous haiku by Tachibana Hokushi, with each line wrapped in a `<p>` tag. Your job is to insert an `<hr />` separator between each paragraph. Your resulting structure should look like this: +W tym przykładzie renderowany jest znany haiku autorstwa Tachibana Hokushi, z każdą linią umieszczoną w tagu `<p>`. Twoim zadaniem jest wstawienie separatora `<hr />` między każdym akapitem. Ostateczna struktura powinna wyglądać tak: ```js <article> - <p>I write, erase, rewrite</p> + <p>Piszę, wymazuję, przepisuję</p> <hr /> - <p>Erase again, and then</p> + <p>Znowu wymazuję, a wtedy</p> <hr /> - <p>A poppy blooms.</p> + <p>Mak zakwita.</p> </article> ``` -A haiku only contains three lines, but your solution should work with any number of lines. Note that `<hr />` elements only appear *between* the `<p>` elements, not in the beginning or the end! +Haiku zawiera tylko trzy linie, ale twoje rozwiązanie powinno działać dla dowolnej liczby linii. Zauważ, że elementy `<hr />` pojawiają się tylko *pomiędzy* elementami `<p>` , nie na początku czy na końcu! <Sandpack> ```js const poem = { lines: [ - 'I write, erase, rewrite', - 'Erase again, and then', - 'A poppy blooms.' + 'Piszę, wymazuję, przepisuję', + 'Znowu wymazuję, a wtedy', + 'Mak zakwita.' ] }; @@ -1141,33 +1142,33 @@ hr { </Sandpack> -(This is a rare case where index as a key is acceptable because a poem's lines will never reorder.) +To rzadki przypadek, w którym indeks użyty jako klucz jest akceptowalny, ponieważ linie wiersza nigdy nie zmienią kolejności. <Hint> -You'll either need to convert `map` to a manual loop, or use a Fragment. +Będziesz musieć albo przekształcić wywołanie funkcji `map()` w pętlę manualną, albo użyć Fragmentu. </Hint> <Solution> -You can write a manual loop, inserting `<hr />` and `<p>...</p>` into the output array as you go: +Możesz napisać pętlę manualną, dodając `<hr />` i `<p>...</p>` do tablicy wynikowej w miarę postępu: <Sandpack> ```js const poem = { lines: [ - 'I write, erase, rewrite', - 'Erase again, and then', - 'A poppy blooms.' + 'Piszę, wymazuję, przepisuję', + 'Znowu wymazuję, a wtedy', + 'Mak zakwita.' ] }; export default function Poem() { let output = []; - // Fill the output array + // Uzupełnij tablicę wynikową poem.lines.forEach((line, i) => { output.push( <hr key={i + '-separator'} /> @@ -1178,7 +1179,7 @@ export default function Poem() { </p> ); }); - // Remove the first <hr /> + // Usuń pierwszy element <hr /> output.shift(); return ( @@ -1206,9 +1207,9 @@ hr { </Sandpack> -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'}`. +Wykorzystanie oryginalnego indeksu linii jako `key` już nie zadziała, ponieważ każdy separator i akapit znajdują się teraz w tej samej tablicy. Niemniej jednak możesz nadać każdemu z nich odrębny klucz, dodając sufiks, np. `key={i + '-text'}`. -Alternatively, you could render a collection of Fragments which contain `<hr />` and `<p>...</p>`. However, the `<>...</>` shorthand syntax doesn't support passing keys, so you'd have to write `<Fragment>` explicitly: +Ewentualnie, możesz wyrenderować kolekcję Fragmentów, które zawierają `<hr />` i `<p>...</p>`. Jednak skrócona składnia `<>...</>` nie wspiera przekazywania kluczy, więc musisz użyć składni `<Fragment>`: <Sandpack> @@ -1217,9 +1218,9 @@ import { Fragment } from 'react'; const poem = { lines: [ - 'I write, erase, rewrite', - 'Erase again, and then', - 'A poppy blooms.' + 'Piszę, wymazuję, przepisuję', + 'Znowu wymazuję, a wtedy', + 'Mak zakwita.' ] }; @@ -1254,7 +1255,7 @@ hr { </Sandpack> -Remember, Fragments (often written as `<> </>`) let you group JSX nodes without adding extra `<div>`s! +Pamiętaj, że Fragmenty (często zapisywane jako `<> </>`) pozwalają grupować węzły JSX bez dodawania elementów `<div>`! </Solution> diff --git a/src/content/learn/responding-to-events.md b/src/content/learn/responding-to-events.md index 17bd087ed..5f3091ed9 100644 --- a/src/content/learn/responding-to-events.md +++ b/src/content/learn/responding-to-events.md @@ -1,24 +1,24 @@ --- -title: Responding to Events +title: Obsługa zdarzeń --- <Intro> -React lets you add *event handlers* to your JSX. Event handlers are your own functions that will be triggered in response to interactions like clicking, hovering, focusing form inputs, and so on. +React pozwala nam dodać *procedury obsługi zdarzeń* (ang. _event handlers_) do naszego JSX-a. Procedury obsługi zdarzeń to twoje własne funkcje, które zostaną wywołane w odpowiedzi na interakcje takie jak klikanie, najeżdżanie kursorem, zaznaczanie pól tekstowych itp. </Intro> <YouWillLearn> -* Different ways to write an event handler -* How to pass event handling logic from a parent component -* How events propagate and how to stop them +* Na jakie sposoby można pisać procedury obsługi zdarzeń +* Jak przekazać logikę obsługi zdarzeń z komponentu rodzica +* Jak zdarzenia są przekazywane i jak je powstrzymać </YouWillLearn> -## Adding event handlers {/*adding-event-handlers*/} +## Dodawanie procedur obsługi zdarzeń {/*adding-event-handlers*/} -To add an event handler, you will first define a function and then [pass it as a prop](/learn/passing-props-to-a-component) to the appropriate JSX tag. For example, here is a button that doesn't do anything yet: +Aby dodać procedurę obsługi zdarzeń, najpierw zdefiniuj funkcję, a następnie [przekaż ją jako właściwość (ang. _prop_)](/learn/passing-props-to-a-component) do odpowiedniego elementu JSX. Na przykład, oto przycisk, który jeszcze nic nie robi: <Sandpack> @@ -26,7 +26,7 @@ To add an event handler, you will first define a function and then [pass it as a export default function Button() { return ( <button> - I don't do anything + Nic nie robię! </button> ); } @@ -34,23 +34,23 @@ export default function Button() { </Sandpack> -You can make it show a message when a user clicks by following these three steps: +Możesz sprawić, by po kliknięciu przez użytkownika przycisk pokazywał wiadomość, wykonując trzy kroki: -1. Declare a function called `handleClick` *inside* your `Button` component. -2. Implement the logic inside that function (use `alert` to show the message). -3. Add `onClick={handleClick}` to the `<button>` JSX. +1. Zadeklaruj funkcję `handleClick` *wewnątrz* swojego komponentu `Button`. +2. Zaimplementuj logikę wewnątrz tej funkcji (użyj `alert` by pokazać wiadomość). +3. Dodaj `onClick={handleClick}` do JSX-a `<button>`. <Sandpack> ```js export default function Button() { function handleClick() { - alert('You clicked me!'); + alert('Nacisnąłeś mnie!'); } return ( <button onClick={handleClick}> - Click me + Naciśnij mnie! </button> ); } @@ -62,77 +62,77 @@ button { margin-right: 10px; } </Sandpack> -You defined the `handleClick` function and then [passed it as a prop](/learn/passing-props-to-a-component) to `<button>`. `handleClick` is an **event handler.** Event handler functions: +Zdefiniowana funkcja `handleClick`, która jest potem [przekazana jako właściwość](/learn/passing-props-to-a-component) do `<button>`, jest **procedurą obsługi zdarzeń.** Funkcje takie jak ta: -* Are usually defined *inside* your components. -* Have names that start with `handle`, followed by the name of the event. +* Są zwykle definiowane *wewnątrz* komponentów +* Mają nazwy zaczynające się od `handle`, po których następuje nazwa zdarzenia. -By convention, it is common to name event handlers as `handle` followed by the event name. You'll often see `onClick={handleClick}`, `onMouseEnter={handleMouseEnter}`, and so on. +Zgodnie z konwencją, nazwy funkcji obsługujących zdarzenia zazwyczaj zaczynają się od `handle`, po którym następuje nazwa zdarzenia. Często zobaczysz składnię taką jak `onClick={handleClick}`, `onMouseEnter={handleMouseEnter}` i podobne. -Alternatively, you can define an event handler inline in the JSX: +Możesz też zdefiniować procedurę obsługi zdarzeń w miejscu wywołania w JSX: ```jsx <button onClick={function handleClick() { - alert('You clicked me!'); + alert('Nacisnąłeś mnie!'); }}> ``` -Or, more concisely, using an arrow function: +Lub zwięźlej, używając funkcji strzałkowej: ```jsx <button onClick={() => { - alert('You clicked me!'); + alert('Nacisnąłeś mnie!'); }}> ``` -All of these styles are equivalent. Inline event handlers are convenient for short functions. +Wszystkie te sposoby dadzą ten sam rezultat. Ten sposób definiowania jest wygodny dla krótkich funkcji. <Pitfall> -Functions passed to event handlers must be passed, not called. For example: +Funkcje przekazywane do procedury obsługi zdarzeń muszą być przekazywane, nie wywoływane. Przykład: -| passing a function (correct) | calling a function (incorrect) | +| przekazanie funkcji (prawidłowo) | wywołanie funkcji (nieprawidłowo) | | -------------------------------- | ---------------------------------- | | `<button onClick={handleClick}>` | `<button onClick={handleClick()}>` | -The difference is subtle. In the first example, the `handleClick` function is passed as an `onClick` event handler. This tells React to remember it and only call your function when the user clicks the button. +Różnica jest subtelna. W pierwszym przykładzie funkcja `handleClick` jest przekazywana do procedury `onClick`. To mówi Reactowi, aby ją zapamiętał i wywołał tylko wtedy, gdy użytkownik naciśnie przycisk. -In the second example, the `()` at the end of `handleClick()` fires the function *immediately* during [rendering](/learn/render-and-commit), without any clicks. This is because JavaScript inside the [JSX `{` and `}`](/learn/javascript-in-jsx-with-curly-braces) executes right away. +W drugim przykładzie `()` na końcu `handleClick()` *natychmiast* wykonuje funkcję podczas [renderowania](/learn/render-and-commit), bez żadnych kliknięć. Dzieje się tak, ponieważ JavaScript wewnątrz [JSX-owych nawiasów `{` i `}`](/learn/javascript-in-jsx-with-curly-braces) wykonuje się od razu. -When you write code inline, the same pitfall presents itself in a different way: +Gdy piszesz kod w jednej linii, ta sama pułapka czeka na ciebie w innej formie: -| passing a function (correct) | calling a function (incorrect) | +| przekazanie funkcji (prawidłowo) | wywołanie funkcji (nieprawidłowo) | | --------------------------------------- | --------------------------------- | | `<button onClick={() => alert('...')}>` | `<button onClick={alert('...')}>` | -Passing inline code like this won't fire on click—it fires every time the component renders: +Przekazywanie kodu w linii, tak jak w poniższym przykładzie, nie uruchomi się na kliknięcie - wywoła się za każdym razem, gdy komponent się wyrenderuje: ```jsx -// This alert fires when the component renders, not when clicked! -<button onClick={alert('You clicked me!')}> +// Ten alert wyskoczy, gdy komponent się renderuje, a nie gdy został naciśnięty! +<button onClick={alert('Nacisnąłeś mnie!')}> ``` -If you want to define your event handler inline, wrap it in an anonymous function like so: +Jeśli chcesz stworzyć własną procedurę obsługi zdarzeń w linii, otocz ją anonimową funkcją w taki sposób: ```jsx -<button onClick={() => alert('You clicked me!')}> +<button onClick={() => alert('Nacisnąłeś mnie!')}> ``` -Rather than executing the code inside with every render, this creates a function to be called later. +Zamiast wywoływać kod wewnątrz przy każdym renderowaniu, stworzy to funkcję do wywołania później. -In both cases, what you want to pass is a function: +W obu przypadkach to co chcesz przekazać, jest funkcją: -* `<button onClick={handleClick}>` passes the `handleClick` function. -* `<button onClick={() => alert('...')}>` passes the `() => alert('...')` function. +* `<button onClick={handleClick}>` przekazuje funkcję `handleClick`. +* `<button onClick={() => alert('...')}>` przekazuje funkcję `() => alert('...')`. -[Read more about arrow functions.](https://javascript.info/arrow-functions-basics) +[Przeczytaj więcej o funkcjach strzałkowych.](https://javascript.info/arrow-functions-basics) </Pitfall> -### Reading props in event handlers {/*reading-props-in-event-handlers*/} +### Odczytywanie właściwości w procedurach obsługi zdarzeń {/*reading-props-in-event-handlers*/} -Because event handlers are declared inside of a component, they have access to the component's props. Here is a button that, when clicked, shows an alert with its `message` prop: +Ponieważ procedury obsługi zdarzeń są deklarowane wewnątrz komponentu, mają dostęp do jego właściwości. Oto przycisk, który po kliknięciu pokaże alert z właściwością `message`: <Sandpack> @@ -148,11 +148,11 @@ function AlertButton({ message, children }) { export default function Toolbar() { return ( <div> - <AlertButton message="Playing!"> - Play Movie + <AlertButton message="Odtwarzanie!"> + Odtwórz film </AlertButton> - <AlertButton message="Uploading!"> - Upload Image + <AlertButton message="Dodawanie!"> + Dodaj obraz </AlertButton> </div> ); @@ -165,13 +165,13 @@ button { margin-right: 10px; } </Sandpack> -This lets these two buttons show different messages. Try changing the messages passed to them. +To pozwala tym dwóm przyciskom pokazywać różne wiadomości. Spróbuj je zmienić. -### Passing event handlers as props {/*passing-event-handlers-as-props*/} +### Przekazywanie procedur obsługi zdarzeń jako właściwości {/*passing-event-handlers-as-props*/} -Often you'll want the parent component to specify a child's event handler. Consider buttons: depending on where you're using a `Button` component, you might want to execute a different function—perhaps one plays a movie and another uploads an image. +Często będziesz chcieć, aby komponent nadrzędny zdefiniował dziecku procedurę obsługi zdarzeń. Przyjrzyj się przyciskom: w zależności od tego, gdzie użyjesz komponentu `Button`, możesz chcieć wykonać inną funkcję - być może jeden odtwarza film, a drugi dodaje obrazek? -To do this, pass a prop the component receives from its parent as the event handler like so: +Aby to zrobić, przekaż właściwość, którą komponent otrzymał od rodzica, jako procedura obsługi w taki sposób: <Sandpack> @@ -186,20 +186,20 @@ function Button({ onClick, children }) { function PlayButton({ movieName }) { function handlePlayClick() { - alert(`Playing ${movieName}!`); + alert(`Odtwarzanie ${movieName}!`); } return ( <Button onClick={handlePlayClick}> - Play "{movieName}" + Odtwórz "{movieName}" </Button> ); } function UploadButton() { return ( - <Button onClick={() => alert('Uploading!')}> - Upload Image + <Button onClick={() => alert('Dodawanie!')}> + Dodaj obraz </Button> ); } @@ -220,22 +220,22 @@ button { margin-right: 10px; } </Sandpack> -Here, the `Toolbar` component renders a `PlayButton` and an `UploadButton`: +Tutaj komponent `Toolbar` renderuje `PlayButton` i `UploadButton`: -- `PlayButton` passes `handlePlayClick` as the `onClick` prop to the `Button` inside. -- `UploadButton` passes `() => alert('Uploading!')` as the `onClick` prop to the `Button` inside. +- `PlayButton` przekazuje `handlePlayClick` jako właściwość `onClick` do wnętrza `Button`. +- `UploadButton` przekazuje `() => alert('Dodawanie!')` jako właściwość `onClick` do wnętrza `Button`. -Finally, your `Button` component accepts a prop called `onClick`. It passes that prop directly to the built-in browser `<button>` with `onClick={onClick}`. This tells React to call the passed function on click. +W końcu twój komponent `Button` akceptuje właściwość zwaną `onClick`. Przekazuje ją bezpośrednio do wbudowanego w przeglądarkę `<button>` z `onClick={onClick}`. Ten wycinek mówi Reactowi, aby wywołał ją na kliknięcie. -If you use a [design system](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969), it's common for components like buttons to contain styling but not specify behavior. Instead, components like `PlayButton` and `UploadButton` will pass event handlers down. +Jeśli używasz [systemu projektowania (ang. _design system_)](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969), często komponenty, takie jak przyciski, posiadają style, ale nie definiują zachowania. Zamiast tego, komponenty typu `PlayButton` czy `UploadButton` będą przekazywały w dół procedury obsługi zdarzeń. -### Naming event handler props {/*naming-event-handler-props*/} +### Nazywanie właściwości procedur obsługi zdarzeń {/*naming-event-handler-props*/} -Built-in components like `<button>` and `<div>` only support [browser event names](/reference/react-dom/components/common#common-props) like `onClick`. However, when you're building your own components, you can name their event handler props any way that you like. +Komponenty wbudowane, takie jak `<button>` i `<div>` wspierają jedynie [nazwy zdarzeń przeglądarki](/reference/react-dom/components/common#common-props) jak `onClick`. Jednak, gdy budujesz własne komponenty, możesz nazywać ich właściwości procedur obsługi jakkolwiek chcesz. -By convention, event handler props should start with `on`, followed by a capital letter. +Według konwencji, właściwości procedur obsługi zdarzeń powinny zaczynać się od `on` i dużej litery tuż po nim. -For example, the `Button` component's `onClick` prop could have been called `onSmash`: +Na przykład, właściwość `onClick` komponentu `Button` mogłaby być nazwana `onSmash`: <Sandpack> @@ -251,11 +251,11 @@ function Button({ onSmash, children }) { export default function App() { return ( <div> - <Button onSmash={() => alert('Playing!')}> - Play Movie + <Button onSmash={() => alert('Odtwarzanie!')}> + Odtwórz film </Button> - <Button onSmash={() => alert('Uploading!')}> - Upload Image + <Button onSmash={() => alert('Dodawanie!')}> + Dodaj zdjęcie </Button> </div> ); @@ -268,9 +268,9 @@ button { margin-right: 10px; } </Sandpack> -In this example, `<button onClick={onSmash}>` shows that the browser `<button>` (lowercase) still needs a prop called `onClick`, but the prop name received by your custom `Button` component is up to you! +W tym przykładzie `<button onClick={onSmash}>` pokazuje, że przeglądarkowy `<button>` (lowercase) nadal potrzebuje właściwości `onClick`, ale jej nazwa otrzymana przez twój własny komponent `Button` może być jaka chcesz! -When your component supports multiple interactions, you might name event handler props for app-specific concepts. For example, this `Toolbar` component receives `onPlayMovie` and `onUploadImage` event handlers: +Gdy twój komponent wspiera wiele różnych interakcji, możesz nazwać właściwości procedur obsługi zdarzeń zgodnie z pojęciami typowymi dla twojej aplikacji. Na przykład, ten komponent `Toolbar` otrzymuje procedury `onPlayMovie` i `onUploadImage`: <Sandpack> @@ -278,8 +278,8 @@ When your component supports multiple interactions, you might name event handler export default function App() { return ( <Toolbar - onPlayMovie={() => alert('Playing!')} - onUploadImage={() => alert('Uploading!')} + onPlayMovie={() => alert('Odtwarzanie!')} + onUploadImage={() => alert('Dodawanie!')} /> ); } @@ -288,10 +288,10 @@ function Toolbar({ onPlayMovie, onUploadImage }) { return ( <div> <Button onClick={onPlayMovie}> - Play Movie + Odtwórz film </Button> <Button onClick={onUploadImage}> - Upload Image + Dodaj zdjęcie </Button> </div> ); @@ -312,19 +312,19 @@ button { margin-right: 10px; } </Sandpack> -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. +Zwróć uwagę na to, że komponent `App` nie musi wiedzieć *co* `Toolbar` zrobi z `onPlayMovie` lub `onUploadImage`. To szczegół w implementacji `Toolbar`. Tutaj, `Toolbar` przekazuje je niżej jako procedury `onClick` do swoich komponentów `Button`, ale później mogą również zostać wywołane skrótem klawiszowym. Nazywanie właściwości po interakcjach specyficznych dla aplikacji np. `onPlayMovie` pozwala ci wygodnie zmieniać, w jaki sposób będą później użyte. <Note> - -Make sure that you use the appropriate HTML tags for your event handlers. For example, to handle clicks, use [`<button onClick={handleClick}>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) instead of `<div onClick={handleClick}>`. Using a real browser `<button>` enables built-in browser behaviors like keyboard navigation. If you don't like the default browser styling of a button and want to make it look more like a link or a different UI element, you can achieve it with CSS. [Learn more about writing accessible markup.](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML) +Upewnij się, że używasz poprawnego tagu HTML dla swoich procedur obsługi zdarzeń. Na przykład, by obsłużyć kliknięcia używaj [`<button onClick={handleClick}>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) zamiast `<div onClick={handleClick}>`. Wykorzystując przeglądarkowy `<button>` możesz używać wbudowanych w nią zachowań takich jak nawigacja klawiaturą. Jeśli nie lubisz domyślnego stylu przycisku, a wolisz by wyglądał bardziej jak link lub inny element interfejsu, możesz to osiągnąć używając CSS. [Więcej o pisaniu HTMLa dostępnego dla wszystkich](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML) + </Note> -## Event propagation {/*event-propagation*/} +## Propagacja zdarzeń {/*event-propagation*/} -Event handlers will also catch events from any children your component might have. We say that an event "bubbles" or "propagates" up the tree: it starts with where the event happened, and then goes up the tree. +Procedury obsługi zdarzeń wyłapią również zdarzenia pochodzące z dowolnego komponentu potomnego. Mówimy wtedy, że zdarzenie "bąbelkuje" (ang. _bubbles_) lub "propaguje" (ang. _propagates_) w górę drzewa: zaczyna się to tam, gdzie zdarzenie miało miejsce, a potem idzie w górę. -This `<div>` contains two buttons. Both the `<div>` *and* each button have their own `onClick` handlers. Which handlers do you think will fire when you click a button? +Ten `<div>` zawiera dwa przyciski. Zarówno element `<div>`, jak i każdy z przycisków mają swoją własną obsługę `onClick`. Jak myślisz, która z nich zostanie uruchomiona, gdy naciśniesz przycisk? <Sandpack> @@ -332,13 +332,13 @@ This `<div>` contains two buttons. Both the `<div>` *and* each button have their export default function Toolbar() { return ( <div className="Toolbar" onClick={() => { - alert('You clicked on the toolbar!'); + alert('Naciśnięto na pasek zadań!'); }}> - <button onClick={() => alert('Playing!')}> - Play Movie + <button onClick={() => alert('Odtwarzanie!')}> + Odtwórz film </button> - <button onClick={() => alert('Uploading!')}> - Upload Image + <button onClick={() => alert('Dodawanie!')}> + Dodaj zdjęcie </button> </div> ); @@ -355,19 +355,19 @@ button { margin: 5px; } </Sandpack> -If you click on either button, its `onClick` will run first, followed by the parent `<div>`'s `onClick`. So two messages will appear. If you click the toolbar itself, only the parent `<div>`'s `onClick` will run. +Naciskając na którykolwiek z przycisków, `onClick` przypisany do nich uruchomi się jako pierwszy. Następnie wykona się `onClick` z nadrzędnego elementu `<div>`, zatem pojawią się dwie wiadomości. Jeśli naciśniesz wprost na pasek, jedynie `onClick` elementu `<div>` zostanie uruchomiony. <Pitfall> -All events propagate in React except `onScroll`, which only works on the JSX tag you attach it to. +W Reakcie przekazywane jest każde zdarzenie poza `onScroll`, które działa tylko na przypisanym do niego tagu JSX </Pitfall> -### Stopping propagation {/*stopping-propagation*/} +### Powstrzymywanie propagacji {/*stopping-propagation*/} -Event handlers receive an **event object** as their only argument. By convention, it's usually called `e`, which stands for "event". You can use this object to read information about the event. +Procedury obsługi zdarzeń otrzymują jako jedyny argument **obiekt zdarzenia** (ang. _event object_). Zwyczajowo nazywany jest `e`, co pochodzi od angielskiego "event". Możesz go użyć do odczytu informacji o zdarzeniu. -That event object also lets you stop the propagation. If you want to prevent an event from reaching parent components, you need to call `e.stopPropagation()` like this `Button` component does: +Poza tym, taki obiekt pozwala zatrzymać propagację. Jeśli chcesz powstrzymać zdarzenie od dotarcia do komponentu nadrzędnego, musisz wywołać `e.stopPropagation()` jak w tym komponencie `Button`: <Sandpack> @@ -386,13 +386,13 @@ function Button({ onClick, children }) { export default function Toolbar() { return ( <div className="Toolbar" onClick={() => { - alert('You clicked on the toolbar!'); + alert('Naciśnięto pasek zadań!'); }}> - <Button onClick={() => alert('Playing!')}> - Play Movie + <Button onClick={() => alert('Odtwarzanie!')}> + Odtwórz film </Button> - <Button onClick={() => alert('Uploading!')}> - Upload Image + <Button onClick={() => alert('Dodawanie!')}> + Dodaj zdjęcie </Button> </div> ); @@ -409,43 +409,43 @@ button { margin: 5px; } </Sandpack> -When you click on a button: +Gdy naciskasz przycisk: -1. React calls the `onClick` handler passed to `<button>`. -2. That handler, defined in `Button`, does the following: - * Calls `e.stopPropagation()`, preventing the event from bubbling further. - * Calls the `onClick` function, which is a prop passed from the `Toolbar` component. -3. That function, defined in the `Toolbar` component, displays the button's own alert. -4. Since the propagation was stopped, the parent `<div>`'s `onClick` handler does *not* run. +1. React wywołuje procedurę `onClick` przekazaną do `<button>`. +2. Ta procedura, zdefiniowana w `Button`, wykonuje następujące czynności: + * Wywołuje `e.stopPropagation()`, powstrzymując zdarzenie przed przekazaniem dalej. + * Wywołuje funkcję `onClick`, która jest właściwością przekazaną z komponentu `Toolbar`. +3. Ta funkcja, zdefiniowana w komponencie `Toolbar`, wyświetla swój własny alert. +4. Ponieważ zatrzymaliśmy przekazanie, procedura `onClick` nadrzędnego elementu `<div>` *nie* uruchamia się. -As a result of `e.stopPropagation()`, clicking on the buttons now only shows a single alert (from the `<button>`) rather than the two of them (from the `<button>` and the parent toolbar `<div>`). Clicking a button is not the same thing as clicking the surrounding toolbar, so stopping the propagation makes sense for this UI. +Jako wynik `e.stopPropagation()`, kliknięcie przycisków pokazuje teraz pojedynczy alert (z `<button>`), zamiast 2 (z `<button>` i nadrzędnego `<div>`a). Naciśnięcie przycisku, to nie to samo co naciśnięcie otaczającego go paska zadań, zatem powstrzymanie przekazania ma sens dla tego interfejsu. <DeepDive> -#### Capture phase events {/*capture-phase-events*/} +#### Przechwytywanie zdarzeń {/*capture-phase-events*/} -In rare cases, you might need to catch all events on child elements, *even if they stopped propagation*. For example, maybe you want to log every click to analytics, regardless of the propagation logic. You can do this by adding `Capture` at the end of the event name: +W niewielu przypadkach możesz musieć przechwycić wszystkie zdarzenia elementów podrzędnych, *nawet jeśli nie są przekazywane*. Na przykład, możesz chcieć zapisać każde kliknięcie w danych analitycznych, bez względu na logikę przekazywań. Możesz to zrobić dodając `Capture` do końca nazwy zdarzenia: ```js -<div onClickCapture={() => { /* this runs first */ }}> +<div onClickCapture={() => { /* to jest uruchamiane najpierw */ }}> <button onClick={e => e.stopPropagation()} /> <button onClick={e => e.stopPropagation()} /> </div> ``` -Each event propagates in three phases: +Każde zdarzenie jest propagowane w trzech fazach: -1. It travels down, calling all `onClickCapture` handlers. -2. It runs the clicked element's `onClick` handler. -3. It travels upwards, calling all `onClick` handlers. +1. Podróżuje w dół, wywołując wszystkie procedury `onClickCapture`. +2. Uruchamia procedurę `onClick` naciśniętego elementu. +3. Podróżuje w górę, wywołując wszystkie procedury `onClick`. -Capture events are useful for code like routers or analytics, but you probably won't use them in app code. +Przechwytywanie zdarzeń przydaje się przy tworzeniu np. routerów czy analityki, ale prawdopodobnie nie znajdziesz dla tego szerszego zastosowania w kodzie aplikacji. </DeepDive> -### Passing handlers as alternative to propagation {/*passing-handlers-as-alternative-to-propagation*/} +### Przekazywanie procedur obsługi jako alternatywa dla propagacji {/*passing-handlers-as-alternative-to-propagation*/} -Notice how this click handler runs a line of code _and then_ calls the `onClick` prop passed by the parent: +Zauważ, jak ta procedura uruchamia linię kodu, _a potem_ wywołuje właściwość `onClick` przekazaną przez rodzica: ```js {4,5} function Button({ onClick, children }) { @@ -460,22 +460,22 @@ function Button({ onClick, children }) { } ``` -You could add more code to this handler before calling the parent `onClick` event handler, too. This pattern provides an *alternative* to propagation. It lets the child component handle the event, while also letting the parent component specify some additional behavior. Unlike propagation, it's not automatic. But the benefit of this pattern is that you can clearly follow the whole chain of code that executes as a result of some event. +Możesz również dodać więcej kodu do tej procedury, przed wywołaniem nadrzędnego `onClick`. Ten wzór pokazuje *alternatywę* dla propagacji. Pozwala ona komponentowi potomnemu zająć się zdarzeniem, podczas gdy ten nadrzędny może określić jakieś dodatkowe zachowanie. W przeciwieństwie do propagacji nie jest to automatyczne, ale plusem tego wzoru jest możliwość prostego podążania za całym ciągiem kodu, który wykonuje się jako wynik jakiegoś zdarzenia -If you rely on propagation and it's difficult to trace which handlers execute and why, try this approach instead. +Jeśli używając propagacji jest ci ciężko prześledzić, które procedury są wykonywane i dlaczego, spróbuj tego podejścia. -### Preventing default behavior {/*preventing-default-behavior*/} +### Powstrzymywanie domyślnego zachowania {/*preventing-default-behavior*/} -Some browser events have default behavior associated with them. For example, a `<form>` submit event, which happens when a button inside of it is clicked, will reload the whole page by default: +Niektóre zdarzenia przeglądarki mają domyślne zachowanie powiązane z nimi. Na przykład zdarzenie wysłania formularza, które następuje, gdy naciśnięty zostanie przycisk w jego wnętrzu, domyślnie przeładuje całą stronę: <Sandpack> ```js export default function Signup() { return ( - <form onSubmit={() => alert('Submitting!')}> + <form onSubmit={() => alert('Wysyłanie!')}> <input /> - <button>Send</button> + <button>Wyślij</button> </form> ); } @@ -487,7 +487,7 @@ button { margin-left: 5px; } </Sandpack> -You can call `e.preventDefault()` on the event object to stop this from happening: +Możesz wywołać `e.preventDefault()` z tego obiektu zdarzenia, aby powstrzymać domyślne zachowanie formularza: <Sandpack> @@ -496,10 +496,10 @@ export default function Signup() { return ( <form onSubmit={e => { e.preventDefault(); - alert('Submitting!'); + alert('Wysyłanie!'); }}> <input /> - <button>Send</button> + <button>Wyślij!</button> </form> ); } @@ -511,28 +511,28 @@ button { margin-left: 5px; } </Sandpack> -Don't confuse `e.stopPropagation()` and `e.preventDefault()`. They are both useful, but are unrelated: +Nie myl `e.stopPropagation()` i `e.preventDefault()`. Oba są użyteczne, ale niepowiązane: -* [`e.stopPropagation()`](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation) stops the event handlers attached to the tags above from firing. -* [`e.preventDefault()` ](https://developer.mozilla.org/docs/Web/API/Event/preventDefault) prevents the default browser behavior for the few events that have it. +* [`e.stopPropagation()`](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation) powstrzymuje procedury obsługi zdarzeń przypisane do tagów wyżej przed uruchomieniem. +* [`e.preventDefault()` ](https://developer.mozilla.org/docs/Web/API/Event/preventDefault) powstrzymuje domyślne zachowanie przeglądarki dla paru zdarzeń, które je posiadają. -## Can event handlers have side effects? {/*can-event-handlers-have-side-effects*/} +## Czy procedury obsługi zdarzeń mogą mieć efekty uboczne? {/*can-event-handlers-have-side-effects*/} -Absolutely! Event handlers are the best place for side effects. +Oczywiście! Procedury obsługi zdarzeń to idealne miejsce na efekty uboczne. -Unlike rendering functions, event handlers don't need to be [pure](/learn/keeping-components-pure), so it's a great place to *change* something—for example, change an input's value in response to typing, or change a list in response to a button press. However, in order to change some information, you first need some way to store it. In React, this is done by using [state, a component's memory.](/learn/state-a-components-memory) You will learn all about it on the next page. +W przeciwieństwie do funkcji renderujących, procedury obsługi zdarzeń nie muszą być [czyste](/learn/keeping-components-pure), więc jest to świetne miejsce by coś *zmienić* - na przykład, wartość pola tekstowego w odpowiedzi na wpisywanie lub listę po naciśnięciu przycisku. Jednakże, aby cokolwiek pozmieniać, musisz wpierw jakoś to przechować. W Reakcie używa się do tego [stanu, czyli pamięci komponentu](/learn/state-a-components-memory). Wszystkiego o tym nauczysz się na następnej stronie. <Recap> -* You can handle events by passing a function as a prop to an element like `<button>`. -* Event handlers must be passed, **not called!** `onClick={handleClick}`, not `onClick={handleClick()}`. -* You can define an event handler function separately or inline. -* Event handlers are defined inside a component, so they can access props. -* You can declare an event handler in a parent and pass it as a prop to a child. -* You can define your own event handler props with application-specific names. -* Events propagate upwards. Call `e.stopPropagation()` on the first argument to prevent that. -* Events may have unwanted default browser behavior. Call `e.preventDefault()` to prevent that. -* Explicitly calling an event handler prop from a child handler is a good alternative to propagation. +* Możesz obsługiwać zdarzenia przekazując funkcję jako właściwość do elementu takiego jak `<button>`. +* Procedury obsługi zdarzeń trzeba przekazać, **a nie wywołać!** Pisz `onClick={handleClick}`, nie `onClick={handleClick()}`. +* Możesz zdefiniować procedurę obsługi zdarzeń osobno lub w linii. +* Procedury obsługi zdarzeń są zdefiniowane wewnątrz komponentu, więc mają dostęp do jego właściwości. +* Możesz stworzyć procedurę obsługi w komponencie nadrzędnym i przekazać ją do podrzędnego. +* Możesz definiować właściwości dla procedur obsługi zdarzeń z nazwami nawiązującymi do aplikacji. +* Zdarzenia przekazywane są do góry. Wywołaj `e.stopPropagation()`, na pierwszym argumencie, by temu zapobiec. +* Zdarzenia mogą mieć niechciane domyślne zachowania. Wywołaj `e.preventDefault()`, by temu zapobiec. +* Wywoływanie procedury obsługi zdarzeń przekazanej przez właściwość od razu w procedurze podrzędnej jest dobrą alternatywą dla propagacji. </Recap> @@ -540,9 +540,9 @@ Unlike rendering functions, event handlers don't need to be [pure](/learn/keepin <Challenges> -#### Fix an event handler {/*fix-an-event-handler*/} +#### Napraw procedurę obsługi zdarzeń {/*fix-an-event-handler*/} -Clicking this button is supposed to switch the page background between white and black. However, nothing happens when you click it. Fix the problem. (Don't worry about the logic inside `handleClick`—that part is fine.) +Naciśnięcie tego przycisku powinno zmieniać tło strony między białym a czarnym. Jednak, gdy go klikniesz to nic się nie dzieje. Napraw błąd (Nie przejmuj się logiką wewnątrz `handleClick` - ta część jest w porządku) <Sandpack> @@ -559,7 +559,7 @@ export default function LightSwitch() { return ( <button onClick={handleClick()}> - Toggle the lights + Przełącz światło </button> ); } @@ -569,7 +569,7 @@ export default function LightSwitch() { <Solution> -The problem is that `<button onClick={handleClick()}>` _calls_ the `handleClick` function while rendering instead of _passing_ it. Removing the `()` call so that it's `<button onClick={handleClick}>` fixes the issue: +Problem polega na tym, że `<button onClick={handleClick()}>` _wywołuje_ funkcję `handleClick` zamiast ją _przekazywać_ podczas renderowania. Usunięcie `()`, aby przycisk został w formie `<button onClick={handleClick}>` naprawi błąd: <Sandpack> @@ -586,7 +586,7 @@ export default function LightSwitch() { return ( <button onClick={handleClick}> - Toggle the lights + Przełącz światła </button> ); } @@ -594,7 +594,7 @@ export default function LightSwitch() { </Sandpack> -Alternatively, you could wrap the call into another function, like `<button onClick={() => handleClick()}>`: +Ewentualnie, możesz opakować wywołanie funkcji w inną funkcję w taki sposób `<button onClick={() => handleClick()}>`: <Sandpack> @@ -611,7 +611,7 @@ export default function LightSwitch() { return ( <button onClick={() => handleClick()}> - Toggle the lights + Przełącz światła </button> ); } @@ -621,11 +621,11 @@ export default function LightSwitch() { </Solution> -#### Wire up the events {/*wire-up-the-events*/} +#### Podłączanie zdarzeń {/*wire-up-the-events*/} -This `ColorSwitch` component renders a button. It's supposed to change the page color. Wire it up to the `onChangeColor` event handler prop it receives from the parent so that clicking the button changes the color. +Komponent `ColorSwitch` renderuje przycisk. Powinien on zmieniać kolor strony. Podłącz go do procedury `onChangeColor`, którą otrzymuje od rodzica tak, aby kliknięcie przycisku faktycznie to zrobiło. -After you do this, notice that clicking the button also increments the page click counter. Your colleague who wrote the parent component insists that `onChangeColor` does not increment any counters. What else might be happening? Fix it so that clicking the button *only* changes the color, and does _not_ increment the counter. +Gdy już to zrobisz zauważ, że kliknięcie przycisku inkrementuje również licznik kliknięć strony. Twój kolega, który napisał komponent nadrzędny uważa, że `onChangeColor` nie inkrementuje żadnych liczników. Co innego może się dziać? Napraw to tak, aby kliknięcie przycisku zmieniło *jedynie* kolor i _nie_ zinkrementowało licznika. <Sandpack> @@ -635,7 +635,7 @@ export default function ColorSwitch({ }) { return ( <button> - Change color + Zmień kolor </button> ); } @@ -669,7 +669,7 @@ export default function App() { <ColorSwitch onChangeColor={handleChangeColor} /> <br /> <br /> - <h2>Clicks on the page: {clicks}</h2> + <h2>Liczba kliknięć na stronie: {clicks}</h2> </div> ); } @@ -679,9 +679,9 @@ export default function App() { <Solution> -First, you need to add the event handler, like `<button onClick={onChangeColor}>`. +Najpierw, musisz dodać procedurę obsługi zdarzeń np. w taki sposób: `<button onClick={onChangeColor}>`. -However, this introduces the problem of the incrementing counter. If `onChangeColor` does not do this, as your colleague insists, then the problem is that this event propagates up, and some handler above does it. To solve this problem, you need to stop the propagation. But don't forget that you should still call `onChangeColor`. +Jednak to wprowadza problem zmiany licznika. Jeśli, jak twierdzi twój kolega, `onChangeColor` go nie zmienia, to problem musi leżeć w przekazywaniu zdarzeń w górę i któraś z nadrzędnych procedur to robi. Aby rozwiązać ten problem, musisz powstrzymać przekazywanie. Nie zapomnij tylko, że nadal musisz wywołać `onChangeColor`. <Sandpack> @@ -694,7 +694,7 @@ export default function ColorSwitch({ e.stopPropagation(); onChangeColor(); }}> - Change color + Zmień kolor </button> ); } @@ -728,7 +728,7 @@ export default function App() { <ColorSwitch onChangeColor={handleChangeColor} /> <br /> <br /> - <h2>Clicks on the page: {clicks}</h2> + <h2>Liczba kliknięć na stronie: {clicks}</h2> </div> ); } diff --git a/src/content/learn/reusing-logic-with-custom-hooks.md b/src/content/learn/reusing-logic-with-custom-hooks.md index 13a556c7b..67de5e97f 100644 --- a/src/content/learn/reusing-logic-with-custom-hooks.md +++ b/src/content/learn/reusing-logic-with-custom-hooks.md @@ -1899,7 +1899,7 @@ export default function Counter() { } ``` -You'll need to write your custom Hook in `useCounter.js` and import it into the `Counter.js` file. +You'll need to write your custom Hook in `useCounter.js` and import it into the `App.js` file. <Sandpack> diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index ac65d2b60..21276c287 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -44,7 +44,7 @@ function ChatRoom({ roomId }) { return ( <> <input value={message} onChange={e => setMessage(e.target.value)} /> - <button onClick={handleSendClick}>Send</button>; + <button onClick={handleSendClick}>Send</button> </> ); } diff --git a/src/content/learn/start-a-new-react-project.md b/src/content/learn/start-a-new-react-project.md index bd5ba6c50..775dabf1c 100644 --- a/src/content/learn/start-a-new-react-project.md +++ b/src/content/learn/start-a-new-react-project.md @@ -1,123 +1,123 @@ --- -title: Start a New React Project +title: Zacznij nowy projekt w Reakcie --- <Intro> -If you want to build a new app or a new website fully with React, we recommend picking one of the React-powered frameworks popular in the community. +Jeśli chcesz zbudować nową aplikację lub stronę internetową wyłącznie za pomocą Reacta, zalecamy wybrać jeden z popularnych wśród społeczności frameworków opartych na Reakcie. </Intro> -You can use React without a framework, however we’ve found that most apps and sites eventually build solutions to common problems such as code-splitting, routing, data fetching, and generating HTML. These problems are common to all UI libraries, not just React. +Możesz użyć Reacta bez żadnego frameworka, jednakże zauważyliśmy, że dla większość aplikacji i stron internetowych prędzej czy później tworzy się rozwiązania dla takich częstych problemów jak dzielenie kodu, nawigacja, pobieranie danych i generowanie kodu HTML. Są to typowe problemy dla wszystkich bibliotek do tworzenia UI, nie tylko dla Reacta. -By starting with a framework, you can get started with React quickly, and avoid essentially building your own framework later. +Zaczynając projekt z użyciem frameworka, możesz szybko zacząć używać Reacta i uniknąć potem tworzenia w zasadzie własnego frameworka. <DeepDive> -#### Can I use React without a framework? {/*can-i-use-react-without-a-framework*/} +#### Czy mogę używać Reacta bez żadnego frameworka? {/*can-i-use-react-without-a-framework*/} -You can definitely use React without a framework--that's how you'd [use React for a part of your page.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) **However, if you're building a new app or a site fully with React, we recommend using a framework.** +Oczywiście, możesz używać Reacta bez żadnego frameworka - w taki sposób [używa się go tylko dla części strony.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) **Jednakże, jeśli budujesz nową aplikację lub stronę w pełni za pomocą Reacta, zalecamy korzystanie z frameworka.** -Here's why. +Oto dlaczego. -Even if you don't need routing or data fetching at first, you'll likely want to add some libraries for them. As your JavaScript bundle grows with every new feature, you might have to figure out how to split code for every route individually. As your data fetching needs get more complex, you are likely to encounter server-client network waterfalls that make your app feel very slow. As your audience includes more users with poor network conditions and low-end devices, you might need to generate HTML from your components to display content early--either on the server, or during the build time. Changing your setup to run some of your code on the server or during the build can be very tricky. +Nawet jeśli początkowo nie potrzebujesz nawigacji ani pobierania danych, prawdopodobnie później będziesz chcieć dodać pewne biblioteki do ich obsługi. W miarę jak twoja paczka kodu rośnie z każdą nową funkcją, możesz musieć zastanowić się, jak podzielić kod dla każdego widoku z osobna. Gdy potrzeby dotyczące pobierania danych stają się bardziej złożone, prawdopodobnie napotkasz problemy związane z kaskadami żądań sieciowych między serwerem a klientem, które sprawiają, że twoja strona będzie działała bardzo wolno. Gdy aplikacja zaczyna obsługiwać więcej użytkowników z kiepskim połączeniem sieciowym i urządzeniami niskiej jakości, możesz potrzebować generować HTML z twoich komponentów, aby wyświetlać zawartość wcześniej - albo na serwerze, albo podczas budowania. Zmiana w celu uruchamiania części kodu na serwerze lub podczas budowania może być bardzo trudna. -**These problems are not React-specific. This is why Svelte has SvelteKit, Vue has Nuxt, and so on.** To solve these problems on your own, you'll need to integrate your bundler with your router and with your data fetching library. It's not hard to get an initial setup working, but there are a lot of subtleties involved in making an app that loads quickly even as it grows over time. You'll want to send down the minimal amount of app code but do so in a single client–server roundtrip, in parallel with any data required for the page. You'll likely want the page to be interactive before your JavaScript code even runs, to support progressive enhancement. You may want to generate a folder of fully static HTML files for your marketing pages that can be hosted anywhere and still work with JavaScript disabled. Building these capabilities yourself takes real work. +**Problemy te nie są specyficzne tylko dla Reacta. Dlatego Svelte korzysta z SvelteKit, Vue z Nuxt itp.** Aby samodzielnie rozwiązać te problemy, będziesz musieć zintegrować swój bundler z bibliotekami do nawigacji i do pobierania danych. Nie jest trudno uzyskać początkową działającą konfigurację, ale istnieje wiele niuansów związanych z tworzeniem aplikacji, która ładuje się szybko nawet w miarę jej wzrostu. Będziesz chcieć przesłać minimalną ilość kodu aplikacji, ale zrób to w jednym cyklu klient-serwer, równolegle z danymi wymaganymi do wygenerowania strony. Prawdopodobnie zależy ci, aby strona była interaktywna jeszcze przed uruchomieniem kodu JavaScript, wspierając tym samym progresywne ulepszanie (ang. _progressive enhancement_). Możesz chcieć generować folder w pełni statycznych plików HTML dla swoich stron marketingowych, które można hostować w dowolnym miejscu i wciąż będą działać nawet przy wyłączonym JavaScripcie. Budowanie tych funkcji samodzielnie wymaga konkretnej pracy. -**React frameworks on this page solve problems like these by default, with no extra work from your side.** They let you start very lean and then scale your app with your needs. Each React framework has a community, so finding answers to questions and upgrading tooling is easier. Frameworks also give structure to your code, helping you and others retain context and skills between different projects. Conversely, with a custom setup it's easier to get stuck on unsupported dependency versions, and you'll essentially end up creating your own framework—albeit one with no community or upgrade path (and if it's anything like the ones we've made in the past, more haphazardly designed). - -If your app has unusual constraints not served well by these frameworks, or you prefer to solve these problems yourself, you can roll your own custom setup with React. Grab `react` and `react-dom` from npm, set up your custom build process with a bundler like [Vite](https://vitejs.dev/) or [Parcel](https://parceljs.org/), and add other tools as you need them for routing, static generation or server-side rendering, and more. +**Wymienione tu frameworki reactowe rozwiązują te problemy bez dodatkowej pracy z twojej strony.** Pozwalają rozpocząć od bardzo podstawowej konfiguracji, a następnie rozwijać aplikację zgodnie z twoimi potrzebami. Każdy framework dla Reacta ma swoją społeczność, co ułatwia znalezienie odpowiedzi na pytania i aktualizację narzędzi. Frameworki te również nadają strukturę twojemu kodowi, pomagając tobie i innym zachować kontekst i umiejętności pomiędzy różnymi projektami. Inaczej, korzystając z niestandardowego rozwiązania, łatwiej jest utknąć na niewspieranych wersjach zależności i w zasadzie skończyć tworząc swój własny framework, bez społeczności i sposobów ulepszeń (i jeśli będzie on w jakiś sposób podobny do tych, które stworzyliśmy wcześniej, będzie on bardziej chaotycznie zaprojektowany). +Jeżeli twoja aplikacja posiada nietypowe ograniczenia, które nie są dobrze obsługiwane przez te frameworki lub wolisz samodzielnie rozwiązać te problemy, możesz stworzyć własne niestandardowe rozwiązanie oparte na Reakcie. Pobierz `react` i `react-dom` z npm, skonfiguruj swój własny proces kompilacji za pomocą bundlera, takiego jak [Vite](https://vitejs.dev/) lub [Parcel](https://parceljs.org/), a następnie dodawaj inne narzędzia, gdy będą ci potrzebne, np. do nawigacji, statycznego generowania lub renderowania po stronie serwera i inne. </DeepDive> -## Production-grade React frameworks {/*production-grade-react-frameworks*/} +## Dojrzałe frameworki reactowe {/*production-grade-react-frameworks*/} -These frameworks support all the features you need to deploy and scale your app in production and are working towards supporting our [full-stack architecture vision](#which-features-make-up-the-react-teams-full-stack-architecture-vision). All of the frameworks we recommend are open source with active communities for support, and can be deployed to your own server or a hosting provider. If you’re a framework author interested in being included on this list, [please let us know](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+). +Frameworki te obsługują wszystkie funkcje, których potrzeba do wdrożenia i skalowania aplikacji na produkcji oraz działają nad wsparciem naszej [wizji architektury full-stack](#which-features-make-up-the-react-teams-full-stack-architecture-vision). Wszystkie polecane przez nas frameworki są otwarte i mają aktywne społeczności z ich wsparciem oraz mogą być wdrożone na własnym serwerze lub u dostawcy hostingu. Jeśli jesteś autorem lub autorką frameworka i chcesz być uwzględniony na tej liście, [daj nam znać](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+). ### Next.js {/*nextjs-pages-router*/} -**[Next.js' Pages Router](https://nextjs.org/) is a full-stack React framework.** It's versatile and lets you create React apps of any size--from a mostly static blog to a complex dynamic application. To create a new Next.js project, run in your terminal: +**[Router stron od Next.js](https://nextjs.org/) to kompleksowy (ang. *full-stack*) framework reactowy.** Jest wszechstronny i pozwala na tworzenie aplikacji reactowych o dowolnym rozmiarze - od prostej, głównie statycznej strony bloga po złożoną, dynamiczną aplikację. Aby utworzyć nowy projekt w Next.js, wywołaj poniższą komendę w terminalu: <TerminalBlock> npx create-next-app@latest </TerminalBlock> -If you're new to Next.js, check out the [learn Next.js course.](https://nextjs.org/learn) +Jeśli Next.js jest dla ciebie nowością, sprawdź [samouczek Next.js](https://nextjs.org/learn). -Next.js is maintained by [Vercel](https://vercel.com/). You can [deploy a Next.js app](https://nextjs.org/docs/app/building-your-application/deploying) to any Node.js or serverless hosting, or to your own server. Next.js also supports a [static export](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports) which doesn't require a server. +Next.js jest rozwijany przez [Vercel](https://vercel.com/). Możesz [wdrożyć aplikację Next.js](https://nextjs.org/docs/app/building-your-application/deploying) na dowolnym hostingu obsługującym Node.js lub usłudze bezserwerowej, lub nawet na własnym serwerze. Next.js obsługuje również [eksport statyczny](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports), który nie wymaga serwera. ### Remix {/*remix*/} -**[Remix](https://remix.run/) is a full-stack React framework with nested routing.** It lets you break your app into nested parts that can load data in parallel and refresh in response to the user actions. To create a new Remix project, run: +**[Remix](https://remix.run/) to kompleksowy framework reactowy z wbudowanym nawigacją.** Pozwala to na podzielenie aplikacji na zagnieżdżone części, które mogą ładować dane równolegle i odświeżać się w odpowiedzi na akcje użytkownika. Aby utworzyć nowy projekt w Remix, uruchom komendę: <TerminalBlock> npx create-remix </TerminalBlock> -If you're new to Remix, check out the Remix [blog tutorial](https://remix.run/docs/en/main/tutorials/blog) (short) and [app tutorial](https://remix.run/docs/en/main/tutorials/jokes) (long). +Jeśli Remix jest dla ciebie czymś nowym, sprawdź [samouczek na blogu](https://remix.run/docs/en/main/tutorials/blog) (krótki) oraz [samouczek z przykładową aplikacją](https://remix.run/docs/en/main/tutorials/jokes) (długi). -Remix is maintained by [Shopify](https://www.shopify.com/). When you create a Remix project, you need to [pick your deployment target](https://remix.run/docs/en/main/guides/deployment). You can deploy a Remix app to any Node.js or serverless hosting by using or writing an [adapter](https://remix.run/docs/en/main/other-api/adapter). +Remix jest utrzymywany przez [Shopify](https://www.shopify.com/). Kiedy tworzysz projekt z użyciem Remiksa, musisz [wybrać platformę docelową](https://remix.run/docs/en/main/guides/deployment). Możesz wdrożyć aplikację opartą na Remiksie na dowolnym hostingu obsługującym Node.js lub na usłudze bezserwerowej, korzystając z [istniejącego lub własnego adaptera](https://remix.run/docs/en/main/other-api/adapter). ### Gatsby {/*gatsby*/} -**[Gatsby](https://www.gatsbyjs.com/) is a React framework for fast CMS-backed websites.** Its rich plugin ecosystem and its GraphQL data layer simplify integrating content, APIs, and services into one website. To create a new Gatsby project, run: +[Gatsby](https://www.gatsbyjs.com/) to framework reactowy stworzony dla szybkich stron internetowych opartych o CMS. Jego bogaty ekosystem wtyczek i warstwa danych GraphQL ułatwiają integrację treści, interfejsów API i usług. Aby utworzyć nowy projekt Gatsby, uruchom komendę: <TerminalBlock> npx create-gatsby </TerminalBlock> -If you're new to Gatsby, check out the [Gatsby tutorial.](https://www.gatsbyjs.com/docs/tutorial/) +Jeśli Gatsby to dla ciebie nowość, sprawdź [samouczek](https://www.gatsbyjs.com/docs/tutorial/). -Gatsby is maintained by [Netlify](https://www.netlify.com/). You can [deploy a fully static Gatsby site](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting) to any static hosting. If you opt into using server-only features, make sure your hosting provider supports them for Gatsby. +Gatsby jest utrzymywane przez [Netlify](https://www.netlify.com/). Możesz [wdrożyć w pełni statyczną stronę stworzoną w Gatsbym](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting) na dowolnym hostingu statycznym. Jeśli zdecydujesz się na korzystanie z funkcji obsługiwanych tylko przez serwer, upewnij się, że twój dostawca hostingu wspiera je dla Gatsby'ego. -### Expo (for native apps) {/*expo*/} +### Expo (dla aplikacji natywnych) {/*expo*/} -**[Expo](https://expo.dev/) is a React framework that lets you create universal Android, iOS, and web apps with truly native UIs.** It provides an SDK for [React Native](https://reactnative.dev/) that makes the native parts easier to use. To create a new Expo project, run: +**[Expo](https://expo.dev/) to framework reactowy, który pozwala tworzyć uniwersalne aplikacje na Androida, iOS oraz webowe z prawdziwie natywnym interfejsem użytkownika.** Dostarcza on SDK dla [React Native](https://reactnative.dev/), które ułatwia korzystanie z natywnych funkcjonalności. Aby utworzyć nowy projekt z Expo, uruchom komendę: <TerminalBlock> npx create-expo-app </TerminalBlock> -If you're new to Expo, check out the [Expo tutorial](https://docs.expo.dev/tutorial/introduction/). +Jeśli Expo jest dla ciebie nowy, zajrzyj do jego [samouczka](https://docs.expo.dev/tutorial/introduction/). + +Expo jest utrzymywane przez [Expo (firmę)](https://expo.dev/about). Budowanie aplikacji z jego pomocą jest darmowe, a te możesz udostępniać w sklepach Google i Apple bez ograniczeń. Expo oferuje także dodatkowe płatne usługi w chmurze. -Expo is maintained by [Expo (the company)](https://expo.dev/about). Building apps with Expo is free, and you can submit them to the Google and Apple app stores without restrictions. Expo additionally provides opt-in paid cloud services. -## Bleeding-edge React frameworks {/*bleeding-edge-react-frameworks*/} +## Nowoczesne frameworki reactowe {/*bleeding-edge-react-frameworks*/} -As we've explored how to continue improving React, we realized that integrating React more closely with frameworks (specifically, with routing, bundling, and server technologies) is our biggest opportunity to help React users build better apps. The Next.js team has agreed to collaborate with us in researching, developing, integrating, and testing framework-agnostic bleeding-edge React features like [React Server Components.](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) +W trakcie eksplorowania możliwości dalszego udoskonalania Reacta zauważyliśmy, że największą szansą, aby pomóc użytkownikom Reacta w budowaniu lepszych aplikacji jest jego ścisła integracja z frameworkami, zwłaszcza pod względem nawigacji, bundlowania i technologii serwerowych. Zespół Next.js zgodził się na współpracę z nami w zakresie badania, rozwoju, integracji i testowania funkcjonalności Reacta z pogranicza frameworków, takich jak [React Server Components.](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) -These features are getting closer to being production-ready every day, and we've been in talks with other bundler and framework developers about integrating them. Our hope is that in a year or two, all frameworks listed on this page will have full support for these features. (If you're a framework author interested in partnering with us to experiment with these features, please let us know!) +Z każdym dniem, funkcjonalności te stają się coraz bliższe użycia w wersji produkcyjnej, a my prowadzimy rozmowy z deweloperami innych bundlerów i frameworków w sprawie ich integracji. Mamy nadzieję, że za rok lub dwa, wszystkie wymienione tu frameworki będą w pełni obsługiwać te funkcjonalności. Jeśli tworzysz framework i interesuje cię współpraca z nami w celu przetestowania tych funkcji, daj nam znać! ### Next.js (App Router) {/*nextjs-app-router*/} -**[Next.js's App Router](https://nextjs.org/docs) is a redesign of the Next.js APIs aiming to fulfill the React team’s full-stack architecture vision.** It lets you fetch data in asynchronous components that run on the server or even during the build. +**[App Router z Next.js](https://nextjs.org/docs) to przeprojektowanie interfejsów API z Next.js, mające na celu zrealizowanie wizji architektury full-stack, przyświecającej zespołowi Reacta.** Pozwala on na pobieranie danych w komponentach asynchronicznych, które uruchamiają się na serwerze lub nawet podczas procesu budowy. -Next.js is maintained by [Vercel](https://vercel.com/). You can [deploy a Next.js app](https://nextjs.org/docs/app/building-your-application/deploying) to any Node.js or serverless hosting, or to your own server. Next.js also supports [static export](https://nextjs.org/docs/app/building-your-application/deploying/static-exports) which doesn't require a server. +Next.js jest rozwijane przez [Vercel](https://vercel.com/). Możesz [wdrożyć aplikację Next.js](https://nextjs.org/docs/app/building-your-application/deploying) na dowolny hosting wspierający Node.js lub rozwiązania chmurowe (ang. _serverless_), a nawet na własny serwer. Next.js obsługuje również [eksport statyczny (ang. _static export_)](https://nextjs.org/docs/app/building-your-application/deploying/static-exports), który nie wymaga serwera. <DeepDive> -#### Which features make up the React team’s full-stack architecture vision? {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} +#### Jakie funkcje składają się na wizję zespołu Reacta dotyczącej architektury full-stack? {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} -Next.js's App Router bundler fully implements the official [React Server Components specification](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md). This lets you mix build-time, server-only, and interactive components in a single React tree. +Bundler App Router z Next.js w pełni implementuje oficjalną [specyfikację React Server Components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md). Pozwala to na łączenie komponentów budowanych podczas kompilacji, budowanych na serwerze oraz interaktywnych w pojedynczym drzewie Reacta. -For example, you can write a server-only React component as an `async` function that reads from a database or from a file. Then you can pass data down from it to your interactive components: +Na przykład, możesz napisać komponent serwerowy jako funkcję `async`, która czyta z bazy danych lub pliku. Następnie możesz przekazywać dane z niego do komponentów interaktywnych: ```js -// This component runs *only* on the server (or during the build). +// Ten komponent jest wywoływany *tylko* po stronie serwera (lub podczas kompilacji). async function Talks({ confId }) { - // 1. You're on the server, so you can talk to your data layer. API endpoint not required. + // 1. Jesteś na serwerze, więc możesz komunikować się z warstwą danych. Użycie API nie jest konieczne. const talks = await db.Talks.findAll({ confId }); - // 2. Add any amount of rendering logic. It won't make your JavaScript bundle larger. + // 2. Dodaj dowolną ilość logiki renderowania. Nie zwiększy to rozmiaru bundla. const videos = talks.map(talk => talk.video); - // 3. Pass the data down to the components that will run in the browser. + // 3. Przekaż dane do komponentów, które będą działały w przeglądarce. return <SearchableVideoList videos={videos} />; } ``` -Next.js's App Router also integrates [data fetching with Suspense](/blog/2022/03/29/react-v18#suspense-in-data-frameworks). This lets you specify a loading state (like a skeleton placeholder) for different parts of your user interface directly in your React tree: +App Router z Next.js zawiera również [pobieranie danych z użyciem Suspense](/blog/2022/03/29/react-v18#suspense-in-data-frameworks). Pozwala to na zdefiniowanie stanu ładowania (na przykład jako skeletonu) dla różnych części interfejsu użytkownika bezpośrednio w drzewie React: ```js <Suspense fallback={<TalksLoading />}> @@ -125,6 +125,6 @@ Next.js's App Router also integrates [data fetching with Suspense](/blog/2022/03 </Suspense> ``` -Server Components and Suspense are React features rather than Next.js features. However, adopting them at the framework level requires buy-in and non-trivial implementation work. At the moment, the Next.js App Router is the most complete implementation. The React team is working with bundler developers to make these features easier to implement in the next generation of frameworks. +Komponenty serwerowe i Suspense są funkcjonalnościami Reacta, a nie samego Next.js. Jednakże ich zaadaptowanie w frameworku wymaga akceptacji i znacznej pracy. W chwili obecnej, App Router z Next.js jest ich najpełniejszą implementacją. Zespół Reacta współpracuje z deweloperami bundlerów, aby ułatwić implementację tych funkcjonalności w frameworkach następnej generacji. </DeepDive> diff --git a/src/content/learn/state-a-components-memory.md b/src/content/learn/state-a-components-memory.md index 0d2942f34..69d973082 100644 --- a/src/content/learn/state-a-components-memory.md +++ b/src/content/learn/state-a-components-memory.md @@ -4,22 +4,22 @@ title: "Stan - Pamięć komponentu" <Intro> -Components often need to change what's on the screen as a result of an interaction. Typing into the form should update the input field, clicking "next" on an image carousel should change which image is displayed, clicking "buy" should put a product in the shopping cart. Components need to "remember" things: the current input value, the current image, the shopping cart. In React, this kind of component-specific memory is called *state*. +Komponenty często muszą zmieniać to, co jest wyświetlane na ekranie w wyniku interakcji. Wpisywanie w formularzu powinno aktualizować jego pole, kliknięcie "następny" w kolejce obrazów powinno zmieniać wyświetlany obraz, kliknięcie "kup" powinno umieścić produkt w koszyku. Komponenty muszą „pamiętać” różne rzeczy: bieżącą wartość pola, bieżący obraz, zawartość koszyka. W Reakcie tego rodzaju pamięć specyficzna dla komponentu nazywana jest *stanem* (ang. _state_). </Intro> <YouWillLearn> -* How to add a state variable with the [`useState`](/reference/react/useState) Hook -* What pair of values the `useState` Hook returns -* How to add more than one state variable -* Why state is called local +* Jak dodać zmienną stanu za pomocą hooka [`useState`](/reference/react/useState) +* Jaką parę wartości zwraca hook `useState` +* Jak dodać więcej niż jedną zmienną stanu +* Dlaczego stan nazywa się lokalnym </YouWillLearn> -## When a regular variable isn’t enough {/*when-a-regular-variable-isnt-enough*/} +## Kiedy zwykła zmienna nie wystarcza {/*when-a-regular-variable-isnt-enough*/} -Here's a component that renders a sculpture image. Clicking the "Next" button should show the next sculpture by changing the `index` to `1`, then `2`, and so on. However, this **won't work** (you can try it!): +Oto komponent, który renderuje obraz rzeźby. Kliknięcie przycisku "Następny" powinno pokazać następną rzeźbę, zmieniając `index` na `1`, potem na `2` i tak dalej. Jednak **to nie zadziała** (możesz spróbować!): <Sandpack> @@ -37,14 +37,14 @@ export default function Gallery() { return ( <> <button onClick={handleClick}> - Next + Następny </button> <h2> <i>{sculpture.name} </i> - by {sculpture.artist} + autorstwa {sculpture.artist} </h2> <h3> - ({index + 1} of {sculptureList.length}) + ({index + 1} z {sculptureList.length}) </h3> <img src={sculpture.url} @@ -62,75 +62,75 @@ export default function Gallery() { export const sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', - description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', + description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.', url: 'https://i.imgur.com/Mx7dA2Y.jpg', - alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' + alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', - description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.', + description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.', url: 'https://i.imgur.com/ZF6s192m.jpg', - alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', - description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."', + description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".', url: 'https://i.imgur.com/aTtVpES.jpg', - alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.' }, { name: 'Moai', - artist: 'Unknown Artist', - description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.', + artist: 'nieznanego', + description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.', url: 'https://i.imgur.com/RCwLEoQm.jpg', - alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', - description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.', + description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.', url: 'https://i.imgur.com/Sd1AgUOm.jpg', - alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', - description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.', + description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.', url: 'https://i.imgur.com/2heNQDcm.jpg', - alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', - description: "Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.", + description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.', url: 'https://i.imgur.com/wIdGuZwm.png', - alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', - description: "Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.", + description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).', url: 'https://i.imgur.com/AlHTAdDm.jpg', - alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.' }, { - name: 'Terracotta Army', - artist: 'Unknown Artist', - description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.', + name: 'Terakotowa Armia', + artist: 'nieznanego', + description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.', url: 'https://i.imgur.com/HMFmH6m.jpg', - alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', - description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.', + description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.', url: 'https://i.imgur.com/rN7hY6om.jpg', - alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.' }, { - name: 'Aureole', + name: 'Aureola', artist: 'Ranjani Shettar', - description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a "fine synthesis of unlikely materials."', + description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.', url: 'https://i.imgur.com/okTpbHhm.jpg', - alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.' }, { name: 'Hippos', - artist: 'Taipei Zoo', - description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.', + artist: 'Ogród Zoologiczny w Taipei', + description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.', url: 'https://i.imgur.com/6o5Vuyu.jpg', - alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.' }]; ``` @@ -151,46 +151,46 @@ button { </Sandpack> -The `handleClick` event handler is updating a local variable, `index`. But two things prevent that change from being visible: +Procedura obsługi zdarzenia `handleClick` aktualizuje lokalną zmienną `index`. Jednak dwie rzeczy uniemożliwiają zobaczenie tej zmiany: -1. **Local variables don't persist between renders.** When React renders this component a second time, it renders it from scratch—it doesn't consider any changes to the local variables. -2. **Changes to local variables won't trigger renders.** React doesn't realize it needs to render the component again with the new data. +1. **Lokalne zmienne nie są zachowywane między renderowaniami.** Gdy React renderuje ten komponent po raz drugi, renderuje go od zera — nie uwzględnia żadnych zmian w lokalnych zmiennych. +2. **Zmiany w lokalnych zmiennych nie wywołają renderowania.** React nie zdaje sobie sprawy, że musi ponownie wyrenderować komponent z nowymi danymi. -To update a component with new data, two things need to happen: +Aby zaktualizować komponent nowymi danymi, muszą zajść dwie rzeczy: -1. **Retain** the data between renders. -2. **Trigger** React to render the component with new data (re-rendering). +1. **Zachować** dane między renderowaniami. +2. **Wywołać** ponowne renderowanie komponentu przez Reacta z nowymi danymi (re-rendering). -The [`useState`](/reference/react/useState) Hook provides those two things: +Hook [`useState`](/reference/react/useState) zapewnia te dwie rzeczy: -1. A **state variable** to retain the data between renders. -2. A **state setter function** to update the variable and trigger React to render the component again. +1. **Zmienną stanu** do zachowania danych między renderowaniami. +2. **Funkcję ustawiająca stan** do aktualizacji zmiennej i wywołania ponownego renderowania komponentu przez Reacta. -## Adding a state variable {/*adding-a-state-variable*/} +## Dodawanie zmiennej stanu {/*adding-a-state-variable*/} -To add a state variable, import `useState` from React at the top of the file: +Aby dodać zmienną stanu, zaimportuj `useState` z Reacta na początku pliku: ```js import { useState } from 'react'; ``` -Then, replace this line: +Następnie, zamień tę linię: ```js let index = 0; ``` -with +na ```js const [index, setIndex] = useState(0); ``` -`index` is a state variable and `setIndex` is the setter function. +`index` jest zmienną stanu a `setIndex` to funkcja ustawiająca stan. -> The `[` and `]` syntax here is called [array destructuring](https://javascript.info/destructuring-assignment) and it lets you read values from an array. The array returned by `useState` always has exactly two items. +> Składnia `[` i `]` nazywana jest [destrukturyzacją tablicy](https://javascript.info/destructuring-assignment) i pozwala na odczyt wartości z tablicy. Tablica zwracana przez `useState` zawsze zawiera dokładnie dwa elementy. -This is how they work together in `handleClick`: +Oto jak współpracują one ze sobą w `handleClick`: ```js function handleClick() { @@ -198,7 +198,7 @@ function handleClick() { } ``` -Now clicking the "Next" button switches the current sculpture: +Teraz kliknięcie przycisku "Następny" przełącza bieżącą rzeźbę: <Sandpack> @@ -217,14 +217,14 @@ export default function Gallery() { return ( <> <button onClick={handleClick}> - Next + Następny </button> <h2> <i>{sculpture.name} </i> - by {sculpture.artist} + autorstwa {sculpture.artist} </h2> <h3> - ({index + 1} of {sculptureList.length}) + ({index + 1} z {sculptureList.length}) </h3> <img src={sculpture.url} @@ -242,75 +242,75 @@ export default function Gallery() { export const sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', - description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', + description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.', url: 'https://i.imgur.com/Mx7dA2Y.jpg', - alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' + alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', - description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.', + description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.', url: 'https://i.imgur.com/ZF6s192m.jpg', - alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', - description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."', + description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".', url: 'https://i.imgur.com/aTtVpES.jpg', - alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.' }, { name: 'Moai', - artist: 'Unknown Artist', - description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.', + artist: 'nieznanego', + description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.', url: 'https://i.imgur.com/RCwLEoQm.jpg', - alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', - description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.', + description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.', url: 'https://i.imgur.com/Sd1AgUOm.jpg', - alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', - description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.', + description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.', url: 'https://i.imgur.com/2heNQDcm.jpg', - alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', - description: "Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.", + description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.', url: 'https://i.imgur.com/wIdGuZwm.png', - alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', - description: "Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.", + description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).', url: 'https://i.imgur.com/AlHTAdDm.jpg', - alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.' }, { - name: 'Terracotta Army', - artist: 'Unknown Artist', - description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.', + name: 'Terakotowa Armia', + artist: 'nieznanego', + description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.', url: 'https://i.imgur.com/HMFmH6m.jpg', - alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', - description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.', + description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.', url: 'https://i.imgur.com/rN7hY6om.jpg', - alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.' }, { - name: 'Aureole', + name: 'Aureola', artist: 'Ranjani Shettar', - description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a "fine synthesis of unlikely materials."', + description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.', url: 'https://i.imgur.com/okTpbHhm.jpg', - alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.' }, { name: 'Hippos', - artist: 'Taipei Zoo', - description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.', + artist: 'Ogród Zoologiczny w Taipei', + description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.', url: 'https://i.imgur.com/6o5Vuyu.jpg', - alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.' }]; ``` @@ -331,57 +331,57 @@ button { </Sandpack> -### Meet your first Hook {/*meet-your-first-hook*/} +### Poznaj swój pierwszy hook {/*meet-your-first-hook*/} -In React, `useState`, as well as any other function starting with "`use`", is called a Hook. +W Reakcie, `useState`, a także każda inna funkcja zaczynająca się od "`use`", nazywana jest hookiem. -*Hooks* are special functions that are only available while React is [rendering](/learn/render-and-commit#step-1-trigger-a-render) (which we'll get into in more detail on the next page). They let you "hook into" different React features. +*Hooki* to specjalne funkcje, które są dostępne tylko podczas [renderowania](/learn/render-and-commit#step-1-trigger-a-render) (o czym opowiemy szczegółowo na następnej stronie). Pozwalają one na "podłączenie się" do różnych funkcji Reacta. -State is just one of those features, but you will meet the other Hooks later. +Stan to tylko jedna z tych funkcji, inne hooki poznasz później. <Pitfall> -**Hooks—functions starting with `use`—can only be called at the top level of your components or [your own Hooks.](/learn/reusing-logic-with-custom-hooks)** You can't call Hooks inside conditions, loops, or other nested functions. Hooks are functions, but it's helpful to think of them as unconditional declarations about your component's needs. You "use" React features at the top of your component similar to how you "import" modules at the top of your file. +**Hooki—funkcje rozpoczynające się od `use`—można wywoływać tylko na najwyższym poziomie komponentów lub [własnych hooków.](/learn/reusing-logic-with-custom-hooks)** Nie możesz wywoływać hooków wewnątrz warunków, pętli ani innych zagnieżdżonych funkcji. hooki to funkcje, ale warto myśleć o nich jako o bezwarunkowych deklaracjach dotyczących potrzeb komponentu. "Używasz" funkcji Reacta na górze komponentu, podobnie jak "importujesz" moduły na górze pliku. </Pitfall> -### Anatomy of `useState` {/*anatomy-of-usestate*/} +### Anatomia `useState` {/*anatomy-of-usestate*/} -When you call [`useState`](/reference/react/useState), you are telling React that you want this component to remember something: +Kiedy wywołujesz [`useState`](/reference/react/useState), informujesz Reacta, że chcesz, aby ten komponent coś zapamiętał: ```js const [index, setIndex] = useState(0); ``` -In this case, you want React to remember `index`. +W tym przypadku chcesz, aby React zapamiętał `index`. <Note> -The convention is to name this pair like `const [something, setSomething]`. You could name it anything you like, but conventions make things easier to understand across projects. +Konwencją jest nadawanie tej parze nazw np. `const [something, setSomething]`. Możesz nadać im dowolne nazwy, jednak konwencje sprawiają, że łatwiej jest zrozumieć kod w różnych projektach. </Note> -The only argument to `useState` is the **initial value** of your state variable. In this example, the `index`'s initial value is set to `0` with `useState(0)`. +Jedynym argumentem dla `useState` jest **początkowa wartość** zmiennej stanu. W tym przykładzie początkowa wartość `index` jest ustawiona na `0` za pomocą `useState(0)`. -Every time your component renders, `useState` gives you an array containing two values: +Za każdym razem, gdy twój komponent jest renderowany, `useState` zwraca tablicę zawierającą dwie wartości: -1. The **state variable** (`index`) with the value you stored. -2. The **state setter function** (`setIndex`) which can update the state variable and trigger React to render the component again. +1. **Zmienną stanu** (`index`) z wartością, którą przechowujesz. +2. **Funkcję ustawiającą stan** (`setIndex`), która może zaktualizować zmienną stanu i spowodować ponowne renderowanie komponentu przez Reacta. -Here's how that happens in action: +Oto jak to wygląda w praktyce: ```js const [index, setIndex] = useState(0); ``` -1. **Your component renders the first time.** Because you passed `0` to `useState` as the initial value for `index`, it will return `[0, setIndex]`. React remembers `0` is the latest state value. -2. **You update the state.** When a user clicks the button, it calls `setIndex(index + 1)`. `index` is `0`, so it's `setIndex(1)`. This tells React to remember `index` is `1` now and triggers another render. -3. **Your component's second render.** React still sees `useState(0)`, but because React *remembers* that you set `index` to `1`, it returns `[1, setIndex]` instead. -4. And so on! +1. **Twój komponent renderuje się po raz pierwszy.** Ponieważ do `useState` przekazano `0` jako początkową wartość dla `index`, zwróci on `[0, setIndex]`. React zapamiętuje, że `0` to najnowsza wartość stanu. +2. **Aktualizujesz stan.** Kiedy użytkownik kliknie przycisk, wywołuje to `setIndex(index + 1)`. `index` wynosi `0`, więc wywołane zostanie `setIndex(1)`. To informuje Reacta, że teraz `index` wynosi `1` i wywołuje ponowne renderowanie. +3. **Drugie renderowanie twojego komponentu.** React nadal widzi `useState(0)`, ale ponieważ React *pamięta*, że ustawiono `index` na `1`, zwraca zamiast tego `[1, setIndex]`. +4. I tak dalej! -## Giving a component multiple state variables {/*giving-a-component-multiple-state-variables*/} +## Nadawanie komponentowi wielu zmiennych stanu {/*giving-a-component-multiple-state-variables*/} -You can have as many state variables of as many types as you like in one component. This component has two state variables, a number `index` and a boolean `showMore` that's toggled when you click "Show details": +Możesz mieć dowolną liczbę zmiennych stanu różnych typów w jednym komponencie. Ten komponent ma dwie zmienne stanu, liczbę `index` oraz zmienną typu boolean `showMore`, która jest przełączana po kliknięciu „Pokaż detale": <Sandpack> @@ -405,17 +405,17 @@ export default function Gallery() { return ( <> <button onClick={handleNextClick}> - Next + Następny </button> <h2> <i>{sculpture.name} </i> - by {sculpture.artist} + autorstwa {sculpture.artist} </h2> <h3> - ({index + 1} of {sculptureList.length}) + ({index + 1} z {sculptureList.length}) </h3> <button onClick={handleMoreClick}> - {showMore ? 'Hide' : 'Show'} details + {showMore ? 'Ukryj' : 'Pokaż'} detale </button> {showMore && <p>{sculpture.description}</p>} <img @@ -431,75 +431,75 @@ export default function Gallery() { export const sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', - description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', + description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.', url: 'https://i.imgur.com/Mx7dA2Y.jpg', - alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' + alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', - description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.', + description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.', url: 'https://i.imgur.com/ZF6s192m.jpg', - alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', - description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."', + description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".', url: 'https://i.imgur.com/aTtVpES.jpg', - alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.' }, { name: 'Moai', - artist: 'Unknown Artist', - description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.', + artist: 'nieznanego', + description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.', url: 'https://i.imgur.com/RCwLEoQm.jpg', - alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', - description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.', + description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.', url: 'https://i.imgur.com/Sd1AgUOm.jpg', - alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', - description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.', + description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.', url: 'https://i.imgur.com/2heNQDcm.jpg', - alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', - description: "Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.", + description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.', url: 'https://i.imgur.com/wIdGuZwm.png', - alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', - description: "Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.", + description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).', url: 'https://i.imgur.com/AlHTAdDm.jpg', - alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.' }, { - name: 'Terracotta Army', - artist: 'Unknown Artist', - description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.', + name: 'Terakotowa Armia', + artist: 'nieznanego', + description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.', url: 'https://i.imgur.com/HMFmH6m.jpg', - alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', - description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.', + description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.', url: 'https://i.imgur.com/rN7hY6om.jpg', - alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.' }, { - name: 'Aureole', + name: 'Aureola', artist: 'Ranjani Shettar', - description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a "fine synthesis of unlikely materials."', + description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.', url: 'https://i.imgur.com/okTpbHhm.jpg', - alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.' }, { name: 'Hippos', - artist: 'Taipei Zoo', - description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.', + artist: 'Ogród Zoologiczny w Taipei', + description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.', url: 'https://i.imgur.com/6o5Vuyu.jpg', - alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.' }]; ``` @@ -520,19 +520,19 @@ button { </Sandpack> -It is a good idea to have multiple state variables if their state is unrelated, like `index` and `showMore` in this example. But if you find that you often change two state variables together, it might be easier to combine them into one. For example, if you have a form with many fields, it's more convenient to have a single state variable that holds an object than state variable per field. Read [Dobieranie struktury stanu](/learn/choosing-the-state-structure) for more tips. +Dobrym pomysłem jest posiadanie wielu zmiennych stanu, jeśli ich stan nie jest powiązany, jak w przypadku `index` i `showMore` w tym przykładzie. Jednak jeśli zauważysz, że często zmieniasz dwie zmienne stanu razem, może być łatwiej połączyć je w jedną. Na przykład, jeśli masz formularz z wieloma polami, wygodniej jest mieć jedną zmienną stanu przechowującą obiekt niż zmienną stanu dla każdego pola. Przeczytaj [dobieranie struktury stanu](/learn/choosing-the-state-structure) po więcej wskazówek. <DeepDive> -#### How does React know which state to return? {/*how-does-react-know-which-state-to-return*/} +#### Skąd React wie, który stan zwrócić? {/*how-does-react-know-which-state-to-return*/} -You might have noticed that the `useState` call does not receive any information about *which* state variable it refers to. There is no "identifier" that is passed to `useState`, so how does it know which of the state variables to return? Does it rely on some magic like parsing your functions? The answer is no. +Być może zauważyłeś/aś, że wywołanie `useState` nie otrzymuje żadnych informacji o tym, do *której* zmiennej stanu się odnosi. Nie ma żadnego "identyfikatora", który jest przekazywany do `useState`, więc skąd React wie, którą zmienną stanu zwrócić? Czy polega on na jakiejś magii, jak analizowanie twoich funkcji? Odpowiedź brzmi: nie. -Instead, to enable their concise syntax, Hooks **rely on a stable call order on every render of the same component.** This works well in practice because if you follow the rule above ("only call Hooks at the top level"), Hooks will always be called in the same order. Additionally, a [linter plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) catches most mistakes. +Zamiast tego, aby umożliwić ich zwięzłą składnię, hooki **opierają się na stabilnej kolejności wywołań przy każdym renderze tego samego komponentu.** Działa to dobrze w praktyce, ponieważ jeśli przestrzegasz zasady powyżej ("wywołuj hooki tylko na najwyższym poziomie"), hooki będą zawsze wywoływane w tej samej kolejności. Dodatkowo [plugin lintera](https://www.npmjs.com/package/eslint-plugin-react-hooks) wychwytuje większość błędów. -Internally, React holds an array of state pairs for every component. It also maintains the current pair index, which is set to `0` before rendering. Each time you call `useState`, React gives you the next state pair and increments the index. You can read more about this mechanism in [React Hooks: Not Magic, Just Arrays.](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e) +Wewnątrz Reacta, dla każdego komponentu przechowywana jest tablica par stanu. React utrzymuje również bieżący indeks pary, który jest ustawiony na `0` przed renderowaniem. Za każdym razem, gdy wywołujesz `useState`, React zwraca kolejną parę stanu i inkrementuje indeks. Możesz poczytać więcej o tym mechanizmie w artykule [React hooks: Not Magic, Just Arrays.](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e) -This example **doesn't use React** but it gives you an idea of how `useState` works internally: +Ten przykład **nie używa Reacta**, ale da ci wyobrażenie o tym, jak `useState` działa od środka: <Sandpack> @@ -540,37 +540,37 @@ This example **doesn't use React** but it gives you an idea of how `useState` wo let componentHooks = []; let currentHookIndex = 0; -// How useState works inside React (simplified). +// Jak działa useState w Reakcie (w uproszczeniu). function useState(initialState) { let pair = componentHooks[currentHookIndex]; if (pair) { - // This is not the first render, - // so the state pair already exists. - // Return it and prepare for next Hook call. + // To nie jest pierwsze renderowanie, + // więc para stanu już istnieje. + // Zwróć ją i przygotuj się na następne wywołanie hooka. currentHookIndex++; return pair; } - // This is the first time we're rendering, - // so create a state pair and store it. + // To pierwszy raz, gdy renderujemy, + // więc tworzymy parę stanu i ją przechowujemy. pair = [initialState, setState]; function setState(nextState) { - // When the user requests a state change, - // put the new value into the pair. + // Kiedy użytkownik zażąda zmiany stanu, + // wstaw nową wartość do pary. pair[0] = nextState; updateDOM(); } - // Store the pair for future renders - // and prepare for the next Hook call. + // Przechowaj parę na przyszłe renderowania + // i przygotuj się na następne wywołanie hooka componentHooks[currentHookIndex] = pair; currentHookIndex++; return pair; } function Gallery() { - // Each useState() call will get the next pair. + // Każde wywołanie useState() zwróci następną parę. const [index, setIndex] = useState(0); const [showMore, setShowMore] = useState(false); @@ -583,14 +583,14 @@ function Gallery() { } let sculpture = sculptureList[index]; - // This example doesn't use React, so - // return an output object instead of JSX. + // Ten przykład nie używa Reacta, więc + // zwróć obiekt wynikowy zamiast JSX. return { onNextClick: handleNextClick, onMoreClick: handleMoreClick, - header: `${sculpture.name} by ${sculpture.artist}`, - counter: `${index + 1} of ${sculptureList.length}`, - more: `${showMore ? 'Hide' : 'Show'} details`, + header: `${sculpture.name} autorstwa ${sculpture.artist}`, + counter: `${index + 1} z ${sculptureList.length}`, + more: `${showMore ? 'Ukryj' : 'Pokaż'} detale`, description: showMore ? sculpture.description : null, imageSrc: sculpture.url, imageAlt: sculpture.alt @@ -598,13 +598,13 @@ function Gallery() { } function updateDOM() { - // Reset the current Hook index - // before rendering the component. + // Zresetuj bieżący indeks hooka + // przed renderowaniem komponentu. currentHookIndex = 0; let output = Gallery(); - // Update the DOM to match the output. - // This is the part React does for you. + // Zaktualizuj DOM, aby pasował do rezultatu. + // To jest część, którą React wykonuje za ciebie. nextButton.onclick = output.onNextClick; header.textContent = output.header; moreButton.onclick = output.onMoreClick; @@ -627,84 +627,84 @@ let image = document.getElementById('image'); let sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', - description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', + description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.', url: 'https://i.imgur.com/Mx7dA2Y.jpg', - alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' + alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', - description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.', + description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.', url: 'https://i.imgur.com/ZF6s192m.jpg', - alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', - description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."', + description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".', url: 'https://i.imgur.com/aTtVpES.jpg', - alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.' }, { name: 'Moai', - artist: 'Unknown Artist', - description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.', + artist: 'nieznanego', + description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.', url: 'https://i.imgur.com/RCwLEoQm.jpg', - alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', - description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.', + description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.', url: 'https://i.imgur.com/Sd1AgUOm.jpg', - alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', - description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.', + description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.', url: 'https://i.imgur.com/2heNQDcm.jpg', - alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', - description: "Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.", + description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.', url: 'https://i.imgur.com/wIdGuZwm.png', - alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', - description: "Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.", + description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).', url: 'https://i.imgur.com/AlHTAdDm.jpg', - alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.' }, { - name: 'Terracotta Army', - artist: 'Unknown Artist', - description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.', + name: 'Terakotowa Armia', + artist: 'nieznanego', + description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.', url: 'https://i.imgur.com/HMFmH6m.jpg', - alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', - description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.', + description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.', url: 'https://i.imgur.com/rN7hY6om.jpg', - alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.' }, { - name: 'Aureole', + name: 'Aureola', artist: 'Ranjani Shettar', - description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a "fine synthesis of unlikely materials."', + description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.', url: 'https://i.imgur.com/okTpbHhm.jpg', - alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.' }, { name: 'Hippos', - artist: 'Taipei Zoo', - description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.', + artist: 'Ogród Zoologiczny w Taipei', + description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.', url: 'https://i.imgur.com/6o5Vuyu.jpg', - alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.' }]; -// Make UI match the initial state. +// Sprawdź, czy UI pasuje do początkowego stanu. updateDOM(); ``` ```html public/index.html <button id="nextButton"> - Next + Następny </button> <h3 id="header"></h3> <button id="moreButton"></button> @@ -724,15 +724,15 @@ button { display: block; margin-bottom: 10px; } </Sandpack> -You don't have to understand it to use React, but you might find this a helpful mental model. +Nie musisz tego rozumieć, aby używać Reacta, ale możesz uznać to za pomocny model mentalny. </DeepDive> -## State is isolated and private {/*state-is-isolated-and-private*/} +## Stan jest izolowany i prywatny {/*state-is-isolated-and-private*/} -State is local to a component instance on the screen. In other words, **if you render the same component twice, each copy will have completely isolated state!** Changing one of them will not affect the other. +Stan jest lokalny dla instancji komponentu na ekranie. Innymi słowy, **jeśli renderujesz ten sam komponent dwa razy, każda kopia będzie miała całkowicie wyizolowany stan!** Zmiana jednego z nich nie wpłynie na drugi. -In this example, the `Gallery` component from earlier is rendered twice with no changes to its logic. Try clicking the buttons inside each of the galleries. Notice that their state is independent: +W tym przykładzie komponent `Gallery` z wcześniejszego przykładu jest renderowany dwukrotnie, bez zmian w jego logice. Spróbuj kliknąć przyciski w każdej z galerii. Zauważ, że ich stan jest niezależny: <Sandpack> @@ -770,17 +770,17 @@ export default function Gallery() { return ( <section> <button onClick={handleNextClick}> - Next + Następny </button> <h2> <i>{sculpture.name} </i> - by {sculpture.artist} + autorstwa {sculpture.artist} </h2> <h3> - ({index + 1} of {sculptureList.length}) + ({index + 1} z {sculptureList.length}) </h3> <button onClick={handleMoreClick}> - {showMore ? 'Hide' : 'Show'} details + {showMore ? 'Ukryj' : 'Pokaż'} detale </button> {showMore && <p>{sculpture.description}</p>} <img @@ -796,75 +796,75 @@ export default function Gallery() { export const sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', - description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', + description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.', url: 'https://i.imgur.com/Mx7dA2Y.jpg', - alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' + alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', - description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.', + description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.', url: 'https://i.imgur.com/ZF6s192m.jpg', - alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', - description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."', + description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".', url: 'https://i.imgur.com/aTtVpES.jpg', - alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.' }, { name: 'Moai', - artist: 'Unknown Artist', - description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.', + artist: 'nieznanego', + description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.', url: 'https://i.imgur.com/RCwLEoQm.jpg', - alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', - description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.', + description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.', url: 'https://i.imgur.com/Sd1AgUOm.jpg', - alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', - description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.', + description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.', url: 'https://i.imgur.com/2heNQDcm.jpg', - alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', - description: "Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.", + description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.', url: 'https://i.imgur.com/wIdGuZwm.png', - alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', - description: "Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.", + description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).', url: 'https://i.imgur.com/AlHTAdDm.jpg', - alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.' }, { - name: 'Terracotta Army', - artist: 'Unknown Artist', - description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.', + name: 'Terakotowa Armia', + artist: 'nieznanego', + description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.', url: 'https://i.imgur.com/HMFmH6m.jpg', - alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', - description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.', + description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.', url: 'https://i.imgur.com/rN7hY6om.jpg', - alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.' }, { - name: 'Aureole', + name: 'Aureola', artist: 'Ranjani Shettar', - description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a "fine synthesis of unlikely materials."', + description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.', url: 'https://i.imgur.com/okTpbHhm.jpg', - alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.' }, { name: 'Hippos', - artist: 'Taipei Zoo', - description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.', + artist: 'Ogród Zoologiczny w Taipei', + description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.', url: 'https://i.imgur.com/6o5Vuyu.jpg', - alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.' }]; ``` @@ -891,21 +891,21 @@ button { </Sandpack> -This is what makes state different from regular variables that you might declare at the top of your module. State is not tied to a particular function call or a place in the code, but it's "local" to the specific place on the screen. You rendered two `<Gallery />` components, so their state is stored separately. +To właśnie sprawia, że stan różni się od zwykłych zmiennych, które możesz zadeklarować na początku swojego modułu. Stan nie jest powiązany z konkretnym wywołaniem funkcji ani miejscem w kodzie, ale jest "lokalny" dla konkretnego miejsca na ekranie. Wyrenderowano dwa komponenty `<Gallery />`, więc ich stan jest przechowywany osobno. -Also notice how the `Page` component doesn't "know" anything about the `Gallery` state or even whether it has any. Unlike props, **state is fully private to the component declaring it.** The parent component can't change it. This lets you add state to any component or remove it without impacting the rest of the components. +Zwróć również uwagę, że komponent `Page` nie "wie" nic o stanie `Gallery` ani nawet o tym, czy w ogóle go posiada. W przeciwieństwie do właściwości (ang. *props*) **stan jest całkowicie prywatny dla komponentu, który go deklaruje.** Komponent nadrzędny nie może go zmienić. Dzięki temu możesz dodać stan do dowolnego komponentu lub go usunąć, nie wpływając na resztę komponentów. -What if you wanted both galleries to keep their states in sync? The right way to do it in React is to *remove* state from child components and add it to their closest shared parent. The next few pages will focus on organizing state of a single component, but we will return to this topic in [Współdzielenie stanu między komponentami.](/learn/sharing-state-between-components) +Co jeśli chcesz, aby obie galerie miały zsynchronizowany stan? W Reakcie właściwym sposobem na to jest *usunięcie* stanu z komponentów potomnych i dodanie go do ich najbliższego wspólnego rodzica. Kolejne strony skupią się na organizowaniu stanu pojedynczego komponentu, ale wrócimy do tego tematu w rozdziale [Współdzielenie stanu między komponentami.](/learn/sharing-state-between-components) <Recap> -* Use a state variable when a component needs to "remember" some information between renders. -* State variables are declared by calling the `useState` Hook. -* Hooks are special functions that start with `use`. They let you "hook into" React features like state. -* Hooks might remind you of imports: they need to be called unconditionally. Calling Hooks, including `useState`, is only valid at the top level of a component or another Hook. -* The `useState` Hook returns a pair of values: the current state and the function to update it. -* You can have more than one state variable. Internally, React matches them up by their order. -* State is private to the component. If you render it in two places, each copy gets its own state. +* Użyj zmiennej stanu, gdy komponent musi "zapamiętać" pewne informacje pomiędzy renderowaniami. +* Zmienne stanu deklaruje się poprzez wywołanie hooka `useState`. +* Hooki to specjalne funkcje rozpoczynające się od `use`. Pozwalają one „podłączyć się” do funkcji Reacta, takich jak stan. +* Hooki mogą przypominać importy: muszą być wywoływane bezwarunkowo. Wywoływanie hooków, w tym `useState`, jest poprawne tylko na najwyższym poziomie komponentu lub innego hooka. +* Hook `useState` zwraca parę wartości: aktualny stan oraz funkcję do jego aktualizacji. +* Możesz mieć więcej niż jedną zmienną stanu. Wewnętrznie React dopasowuje je według kolejności. +* Stan jest prywatny dla komponentu. Jeśli renderujesz go w dwóch miejscach, każda kopia ma swój własny stan. </Recap> @@ -913,11 +913,11 @@ What if you wanted both galleries to keep their states in sync? The right way to <Challenges> -#### Complete the gallery {/*complete-the-gallery*/} +#### Dokończ galerię {/*complete-the-gallery*/} -When you press "Next" on the last sculpture, the code crashes. Fix the logic to prevent the crash. You may do this by adding extra logic to event handler or by disabling the button when the action is not possible. +Kiedy naciśniesz "Następny" na ostatniej rzeźbie, kod powoduje błąd. Napraw logikę, aby uniknąć tego błędu. Możesz to zrobić, dodając dodatkową logikę do obsługi zdarzenia lub wyłączając przycisk, gdy akcja nie jest możliwa. -After fixing the crash, add a "Previous" button that shows the previous sculpture. It shouldn't crash on the first sculpture. +Po naprawieniu błędu, dodaj przycisk "Poprzedni", który wyświetli poprzednią rzeźbę. Nie powinien on powodować błędu na pierwszej rzeźbie. <Sandpack> @@ -941,17 +941,17 @@ export default function Gallery() { return ( <> <button onClick={handleNextClick}> - Next + Następny </button> <h2> <i>{sculpture.name} </i> - by {sculpture.artist} + autorstwa {sculpture.artist} </h2> <h3> - ({index + 1} of {sculptureList.length}) + ({index + 1} z {sculptureList.length}) </h3> <button onClick={handleMoreClick}> - {showMore ? 'Hide' : 'Show'} details + {showMore ? 'Ukryj' : 'Pokaż'} detale </button> {showMore && <p>{sculpture.description}</p>} <img @@ -967,75 +967,75 @@ export default function Gallery() { export const sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', - description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', + description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.', url: 'https://i.imgur.com/Mx7dA2Y.jpg', - alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' + alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', - description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.', + description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.', url: 'https://i.imgur.com/ZF6s192m.jpg', - alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', - description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."', + description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".', url: 'https://i.imgur.com/aTtVpES.jpg', - alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.' }, { name: 'Moai', - artist: 'Unknown Artist', - description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.', + artist: 'nieznanego', + description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.', url: 'https://i.imgur.com/RCwLEoQm.jpg', - alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', - description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.', + description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.', url: 'https://i.imgur.com/Sd1AgUOm.jpg', - alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', - description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.', + description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.', url: 'https://i.imgur.com/2heNQDcm.jpg', - alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', - description: "Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.", + description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.', url: 'https://i.imgur.com/wIdGuZwm.png', - alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', - description: "Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.", + description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).', url: 'https://i.imgur.com/AlHTAdDm.jpg', - alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.' }, { - name: 'Terracotta Army', - artist: 'Unknown Artist', - description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.', + name: 'Terakotowa Armia', + artist: 'nieznanego', + description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.', url: 'https://i.imgur.com/HMFmH6m.jpg', - alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', - description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.', + description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.', url: 'https://i.imgur.com/rN7hY6om.jpg', - alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.' }, { - name: 'Aureole', + name: 'Aureola', artist: 'Ranjani Shettar', - description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a "fine synthesis of unlikely materials."', + description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.', url: 'https://i.imgur.com/okTpbHhm.jpg', - alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.' }, { name: 'Hippos', - artist: 'Taipei Zoo', - description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.', + artist: 'Ogród Zoologiczny w Taipei', + description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.', url: 'https://i.imgur.com/6o5Vuyu.jpg', - alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.' }]; ``` @@ -1059,7 +1059,7 @@ img { width: 120px; height: 120px; } <Solution> -This adds a guarding condition inside both event handlers and disables the buttons when needed: +Ten kod dodaje warunek zabezpieczający w obu obsługach zdarzeń i wyłącza przyciski, gdy jest to konieczne: <Sandpack> @@ -1097,23 +1097,23 @@ export default function Gallery() { onClick={handlePrevClick} disabled={!hasPrev} > - Previous + Poprzedni </button> <button onClick={handleNextClick} disabled={!hasNext} > - Next + Następny </button> <h2> <i>{sculpture.name} </i> - by {sculpture.artist} + autorstwa {sculpture.artist} </h2> <h3> ({index + 1} of {sculptureList.length}) </h3> <button onClick={handleMoreClick}> - {showMore ? 'Hide' : 'Show'} details + {showMore ? 'Ukryj' : 'Pokaż'} detale </button> {showMore && <p>{sculpture.description}</p>} <img @@ -1129,75 +1129,75 @@ export default function Gallery() { export const sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', - description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', + description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.', url: 'https://i.imgur.com/Mx7dA2Y.jpg', - alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' + alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', - description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.', + description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.', url: 'https://i.imgur.com/ZF6s192m.jpg', - alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.' + alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', - description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."', + description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".', url: 'https://i.imgur.com/aTtVpES.jpg', - alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.' + alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.' }, { name: 'Moai', - artist: 'Unknown Artist', - description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.', + artist: 'nieznanego', + description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.', url: 'https://i.imgur.com/RCwLEoQm.jpg', - alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.' + alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', - description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.', + description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.', url: 'https://i.imgur.com/Sd1AgUOm.jpg', - alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.' + alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', - description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.', + description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.', url: 'https://i.imgur.com/2heNQDcm.jpg', - alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.' + alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', - description: "Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.", + description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.', url: 'https://i.imgur.com/wIdGuZwm.png', - alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.' + alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', - description: "Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.", + description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).', url: 'https://i.imgur.com/AlHTAdDm.jpg', - alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.' + alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.' }, { - name: 'Terracotta Army', - artist: 'Unknown Artist', - description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.', + name: 'Terakotowa Armia', + artist: 'nieznanego', + description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.', url: 'https://i.imgur.com/HMFmH6m.jpg', - alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.' + alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', - description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.', + description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.', url: 'https://i.imgur.com/rN7hY6om.jpg', - alt: 'A black matte sculpture where the individual elements are initially indistinguishable.' + alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.' }, { - name: 'Aureole', + name: 'Aureola', artist: 'Ranjani Shettar', - description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a "fine synthesis of unlikely materials."', + description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.', url: 'https://i.imgur.com/okTpbHhm.jpg', - alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.' + alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.' }, { name: 'Hippos', - artist: 'Taipei Zoo', - description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.', + artist: 'Ogród Zoologiczny w Taipei', + description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.', url: 'https://i.imgur.com/6o5Vuyu.jpg', - alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' + alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.' }]; ``` @@ -1219,13 +1219,13 @@ img { width: 120px; height: 120px; } </Sandpack> -Notice how `hasPrev` and `hasNext` are used *both* for the returned JSX and inside the event handlers! This handy pattern works because event handler functions ["close over"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) any variables declared while rendering. +Zauważ, jak `hasPrev` i `hasNext` są używane *zarówno* w zwróconym JSX jak i w obsługach zdarzeń! Ten przydatny wzorzec działa, ponieważ funkcje obsługi zdarzeń ["zamykają się"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) nad wszystkimi zmiennymi deklarowanymi podczas renderowania. </Solution> -#### Fix stuck form inputs {/*fix-stuck-form-inputs*/} +#### Napraw zablokowane pola formularza {/*fix-stuck-form-inputs*/} -When you type into the input fields, nothing appears. It's like the input values are "stuck" with empty strings. The `value` of the first `<input>` is set to always match the `firstName` variable, and the `value` for the second `<input>` is set to always match the `lastName` variable. This is correct. Both inputs have `onChange` event handlers, which try to update the variables based on the latest user input (`e.target.value`). However, the variables don't seem to "remember" their values between re-renders. Fix this by using state variables instead. +Kiedy wpisujesz dane w pola formularza, nic się nie pojawia. Wygląda to tak, jakby wartości wejściowe były „zablokowane” na pustych ciągach. Dla pierwszego `<input>`, `value` jest ustawiony tak, aby zawsze pasował do zmiennej `firstName` a `value` drugiego `<input>` jest ustawiony tak, aby zawsze pasowała do zmiennej `lastName`. Tak powinno być. Oba pola mają obsługiwane zdarzenie `onChange`, które próbuje zaktualizować zmienne na podstawie najnowszych danych wejściowych użytkownika (`e.target.value`). Jednak zmienne wydają się nie "pamiętać" swoich wartości między renderowaniami. Napraw to, używając zamiast tego zmiennych stanu. <Sandpack> @@ -1250,16 +1250,16 @@ export default function Form() { return ( <form onSubmit={e => e.preventDefault()}> <input - placeholder="First name" + placeholder="Imię" value={firstName} onChange={handleFirstNameChange} /> <input - placeholder="Last name" + placeholder="Nazwisko" value={lastName} onChange={handleLastNameChange} /> - <h1>Hi, {firstName} {lastName}</h1> + <h1>Witaj, {firstName} {lastName}</h1> <button onClick={handleReset}>Reset</button> </form> ); @@ -1274,7 +1274,7 @@ h1 { margin-top: 10px; } <Solution> -First, import `useState` from React. Then replace `firstName` and `lastName` with state variables declared by calling `useState`. Finally, replace every `firstName = ...` assignment with `setFirstName(...)`, and do the same for `lastName`. Don't forget to update `handleReset` too so that the reset button works. +Po pierwsze, zaimportuj `useState` z Reacta. Następnie zamień `firstName` i `lastName`na zmienne stanu zadeklarowane za pomocą `useState`. Na końcu zamień każde przypisanie `firstName = ...` na `setFirstName(...)` oraz zrób to samo dla `lastName`. Nie zapomnij także zaktualizować `handleReset`, aby przycisk resetowania mógł działać. <Sandpack> @@ -1301,16 +1301,16 @@ export default function Form() { return ( <form onSubmit={e => e.preventDefault()}> <input - placeholder="First name" + placeholder="Imię" value={firstName} onChange={handleFirstNameChange} /> <input - placeholder="Last name" + placeholder="Nazwisko" value={lastName} onChange={handleLastNameChange} /> - <h1>Hi, {firstName} {lastName}</h1> + <h1>Witaj, {firstName} {lastName}</h1> <button onClick={handleReset}>Reset</button> </form> ); @@ -1325,13 +1325,13 @@ h1 { margin-top: 10px; } </Solution> -#### Fix a crash {/*fix-a-crash*/} +#### Napraw błąd {/*fix-a-crash*/} -Here is a small form that is supposed to let the user leave some feedback. When the feedback is submitted, it's supposed to display a thank-you message. However, it crashes with an error message saying "Rendered fewer hooks than expected". Can you spot the mistake and fix it? +Oto mały formularz, który ma pozwolić użytkownikowi zostawić opinię. Kiedy opinia zostanie wysłana, ma się wyświetlić wiadomość z podziękowaniem. Jednak aplikacja wywołuje błąd z komunikatem "Rendered fewer hooks than expected". Czy potrafisz znaleźć błąd i go naprawić? <Hint> -Are there any limitations on _where_ Hooks may be called? Does this component break any rules? Check if there are any comments disabling the linter checks--this is where the bugs often hide! +Czy istnieją jakieś ograniczenia dotyczące _gdzie_ można wywoływać hooki? Does this component break any rules? Czy ten komponent łamie jakieś zasady? Sprawdź, czy w kodzie znajdują się komentarze wyłączające sprawdzanie przez lintera — to tam często ukrywają się błędy! </Hint> @@ -1343,23 +1343,23 @@ import { useState } from 'react'; export default function FeedbackForm() { const [isSent, setIsSent] = useState(false); if (isSent) { - return <h1>Thank you!</h1>; + return <h1>Dziękuję!</h1>; } else { // eslint-disable-next-line const [message, setMessage] = useState(''); return ( <form onSubmit={e => { e.preventDefault(); - alert(`Sending: "${message}"`); + alert(`Wysyłanie: "${message}"`); setIsSent(true); }}> <textarea - placeholder="Message" + placeholder="Wiadomość" value={message} onChange={e => setMessage(e.target.value)} /> <br /> - <button type="submit">Send</button> + <button type="submit">Wyślij</button> </form> ); } @@ -1370,9 +1370,9 @@ export default function FeedbackForm() { <Solution> -Hooks can only be called at the top level of the component function. Here, the first `isSent` definition follows this rule, but the `message` definition is nested in a condition. +Hooki mogą być wywoływane tylko na najwyższym poziomie funkcji komponentu. Tutaj pierwsza definicja `isSent` przestrzega tej zasady, ale definicja `message` jest zagnieżdżona w warunku. -Move it out of the condition to fix the issue: +Przenieś ją poza warunek, aby naprawić problem: <Sandpack> @@ -1384,21 +1384,21 @@ export default function FeedbackForm() { const [message, setMessage] = useState(''); if (isSent) { - return <h1>Thank you!</h1>; + return <h1>Dziękuję!</h1>; } else { return ( <form onSubmit={e => { e.preventDefault(); - alert(`Sending: "${message}"`); + alert(`Wysyłanie: "${message}"`); setIsSent(true); }}> <textarea - placeholder="Message" + placeholder="Wiadomość" value={message} onChange={e => setMessage(e.target.value)} /> <br /> - <button type="submit">Send</button> + <button type="submit">Wyślij</button> </form> ); } @@ -1407,9 +1407,9 @@ export default function FeedbackForm() { </Sandpack> -Remember, Hooks must be called unconditionally and always in the same order! +Pamiętaj, że hooki muszą być wywoływane bezwarunkowo i zawsze w tej samej kolejności! -You could also remove the unnecessary `else` branch to reduce the nesting. However, it's still important that all calls to Hooks happen *before* the first `return`. +Możesz również usunąć niepotrzebną gałąź `else`, aby zredukować zagnieżdżenie. Ważne jest jednak, aby wszystkie wywołania hooków miały miejsce *przed* pierwszym `return`. <Sandpack> @@ -1421,22 +1421,22 @@ export default function FeedbackForm() { const [message, setMessage] = useState(''); if (isSent) { - return <h1>Thank you!</h1>; + return <h1>Dziękuję!</h1>; } return ( <form onSubmit={e => { e.preventDefault(); - alert(`Sending: "${message}"`); + alert(`Wysyłanie: "${message}"`); setIsSent(true); }}> <textarea - placeholder="Message" + placeholder="Wiadomość" value={message} onChange={e => setMessage(e.target.value)} /> <br /> - <button type="submit">Send</button> + <button type="submit">Wyślij</button> </form> ); } @@ -1444,19 +1444,19 @@ export default function FeedbackForm() { </Sandpack> -Try moving the second `useState` call after the `if` condition and notice how this breaks it again. +Spróbuj przenieść drugie wywołanie `useState` po warunku `if` i zauważ, jak to znowu powoduje błąd. -If your linter is [configured for React](/learn/editor-setup#linting), you should see a lint error when you make a mistake like this. If you don't see an error when you try the faulty code locally, you need to set up linting for your project. +Jeśli Twój linter jest [skonfigurowany pod Reacta](/learn/editor-setup#linting), powinien wyświetlić się błąd lintera, gdy popełnisz pomyłkę taką jak ta. Jeśli nie widzisz błędu, gdy próbujesz uruchomić błędny kod lokalnie, musisz skonfigurować lintera dla swojego projektu. </Solution> -#### Remove unnecessary state {/*remove-unnecessary-state*/} +#### Usuń niepotrzebny stan {/*remove-unnecessary-state*/} -When the button is clicked, this example should ask for the user's name and then display an alert greeting them. You tried to use state to keep the name, but for some reason it always shows "Hello, !". +Kiedy przycisk jest kliknięty, ten przykład powinien zapytać o imię użytkownika, a następnie wyświetlić alert z powitaniem. Próbowano użyć stanu do przechowywania imienia, ale z jakiegoś powodu zawsze wyświetla się "Witaj, !". -To fix this code, remove the unnecessary state variable. (We will discuss about [why this didn't work](/learn/state-as-a-snapshot) later.) +Aby naprawić ten kod, usuń niepotrzebną zmienną stanu. (Omówimy, [dlaczego to nie zadziałało](/learn/state-as-a-snapshot) później.) -Can you explain why this state variable was unnecessary? +Czy możesz wyjaśnić, dlaczego ta zmienna stanu była niepotrzebna? <Sandpack> @@ -1467,13 +1467,13 @@ export default function FeedbackForm() { const [name, setName] = useState(''); function handleClick() { - setName(prompt('What is your name?')); - alert(`Hello, ${name}!`); + setName(prompt('Jak masz na imię?')); + alert(`Witaj, ${name}!`); } return ( <button onClick={handleClick}> - Greet + Powitanie </button> ); } @@ -1483,20 +1483,20 @@ export default function FeedbackForm() { <Solution> -Here is a fixed version that uses a regular `name` variable declared in the function that needs it: +Oto poprawiona wersja, która używa zwykłej zmiennej `name` zadeklarowanej w funkcji, która jej potrzebuje: <Sandpack> ```js export default function FeedbackForm() { function handleClick() { - const name = prompt('What is your name?'); - alert(`Hello, ${name}!`); + const name = prompt('Jak masz na imię?'); + alert(`Witaj, ${name}!`); } return ( <button onClick={handleClick}> - Greet + Powitanie </button> ); } @@ -1504,7 +1504,7 @@ export default function FeedbackForm() { </Sandpack> -A state variable is only necessary to keep information between re-renders of a component. Within a single event handler, a regular variable will do fine. Don't introduce state variables when a regular variable works well. +Zmienna stanu jest konieczna tylko wtedy, gdy musisz zachować informacje między kolejnymi renderowaniami komponentu. W ramach pojedynczego obsługiwania zdarzenia wystarczy zwykła zmienna. Nie wprowadzaj zmiennych stanu, gdy zwykła zmienna działa dobrze. </Solution> diff --git a/src/content/learn/state-as-a-snapshot.md b/src/content/learn/state-as-a-snapshot.md index df4eddbd6..35d00602e 100644 --- a/src/content/learn/state-as-a-snapshot.md +++ b/src/content/learn/state-as-a-snapshot.md @@ -1,27 +1,27 @@ --- -title: State as a Snapshot +title: Stan jako migawka --- <Intro> -State variables might look like regular JavaScript variables that you can read and write to. However, state behaves more like a snapshot. Setting it does not change the state variable you already have, but instead triggers a re-render. +Zmienne stanu mogą wyglądać jak zwykłe zmienne javascriptowe, które można odczytywać i zapisywać. Jednak stan zachowuje się bardziej jak migawka. Ustawienie go nie zmienia zmiennej stanu, którą już masz, ale zamiast tego wyzwala ponowne renderowanie. </Intro> <YouWillLearn> -* How setting state triggers re-renders -* When and how state updates -* Why state does not update immediately after you set it -* How event handlers access a "snapshot" of the state +* Jak ustawienie stanu wyzwala ponowne renderowanie +* Kiedy i jak stan się aktualizuje +* Dlaczego stan nie aktualizuje się natychmiast po jego ustawieniu +* Jak procedury obsługi zdarzeń uzyskują dostęp do "migawki" stanu </YouWillLearn> -## Setting state triggers renders {/*setting-state-triggers-renders*/} +## Ustawianie stanu wyzwala ponowne renderowanie {/*setting-state-triggers-renders*/} -You might think of your user interface as changing directly in response to the user event like a click. In React, it works a little differently from this mental model. On the previous page, you saw that [setting state requests a re-render](/learn/render-and-commit#step-1-trigger-a-render) from React. This means that for an interface to react to the event, you need to *update the state*. +Możesz myśleć, że twój interfejs użytkownika zmienia się bezpośrednio w odpowiedzi na zdarzenia użytkownika, takie jak kliknięcie. W Reakcie działa to nieco inaczej. Na poprzedniej stronie mogliśmy zobaczyć, że [ustawienie stanu wysyła żądanie ponownego renderowania](/learn/render-and-commit#step-1-trigger-a-render) do Reacta. Oznacza to, że aby interfejs zareagował na zdarzenie, musisz *zaktualizować stan*. -In this example, when you press "send", `setIsSent(true)` tells React to re-render the UI: +Gdy naciśniesz "Wyślij" w poniższym przykładzie, wywołanie `setIsSent(true)` informuje Reacta, aby ponownie wyrenderował interfejs użytkownika: <Sandpack> @@ -30,9 +30,9 @@ import { useState } from 'react'; export default function Form() { const [isSent, setIsSent] = useState(false); - const [message, setMessage] = useState('Hi!'); + const [message, setMessage] = useState('Cześć!'); if (isSent) { - return <h1>Your message is on its way!</h1> + return <h1>Twoja wiadomość jest w drodze!</h1> } return ( <form onSubmit={(e) => { @@ -41,11 +41,11 @@ export default function Form() { sendMessage(message); }}> <textarea - placeholder="Message" + placeholder="Wiadomość" value={message} onChange={e => setMessage(e.target.value)} /> - <button type="submit">Send</button> + <button type="submit">Wyślij</button> </form> ); } @@ -61,43 +61,43 @@ label, textarea { margin-bottom: 10px; display: block; } </Sandpack> -Here's what happens when you click the button: +Oto co dzieje się, gdy klikniesz przycisk: -1. The `onSubmit` event handler executes. -2. `setIsSent(true)` sets `isSent` to `true` and queues a new render. -3. React re-renders the component according to the new `isSent` value. +1. Wykonuje się procedura obsługi zdarzenia `onSubmit`. +2. Wywołanie `setIsSent(true)` ustawia `isSent` na `true` i dodaje do kolejki nowe renderowanie. +3. React ponownie renderuje komponent zgodnie z nową wartością `isSent`. -Let's take a closer look at the relationship between state and rendering. +Przyjrzyjmy się bliżej związkowi między stanem a renderowaniem. -## Rendering takes a snapshot in time {/*rendering-takes-a-snapshot-in-time*/} +## Renderowanie tworzy migawkę danego momentu {/*rendering-takes-a-snapshot-in-time*/} -["Rendering"](/learn/render-and-commit#step-2-react-renders-your-components) means that React is calling your component, which is a function. The JSX you return from that function is like a snapshot of the UI in time. Its props, event handlers, and local variables were all calculated **using its state at the time of the render.** +["Renderowanie"](/learn/render-and-commit#step-2-react-renders-your-components) oznacza, że React wywołuje twój komponent, który jest funkcją. Zwracany przez tę funkcję JSX jest jak migawka interfejsu użytkownika w danym momencie. Jego właściwości, procedury obsługi zdarzeń i zmienne lokalne zostały obliczone **na podstawie stanu w momencie renderowania.** -Unlike a photograph or a movie frame, the UI "snapshot" you return is interactive. It includes logic like event handlers that specify what happens in response to inputs. React updates the screen to match this snapshot and connects the event handlers. As a result, pressing a button will trigger the click handler from your JSX. +W przeciwieństwie do fotografii czy klatki filmu, zwracana przez ciebie "migawka" interfejsu użytkownika jest interaktywna. Zawiera logikę, taką jak procedury obsługi zdarzeń, które określają, co się stanie w odpowiedzi na dane wejściowe. React aktualizuje ekran, aby dopasować go do tej migawki i podłącza procedury obsługi zdarzeń. W rezultacie naciśnięcie przycisku uruchomi procedurę obsługi kliknięcia z twojego JSX. -When React re-renders a component: +Kiedy React ponownie renderuje komponent: -1. React calls your function again. -2. Your function returns a new JSX snapshot. -3. React then updates the screen to match the snapshot your function returned. +1. React ponownie wywołuje twoją funkcję. +2. Twoja funkcja zwraca nową migawkę JSX. +3. React następnie aktualizuje ekran, aby dopasować go do migawki zwróconej przez twoją funkcję. <IllustrationBlock sequential> - <Illustration caption="React executing the function" src="/images/docs/illustrations/i_render1.png" /> - <Illustration caption="Calculating the snapshot" src="/images/docs/illustrations/i_render2.png" /> - <Illustration caption="Updating the DOM tree" src="/images/docs/illustrations/i_render3.png" /> + <Illustration caption="React wykonuje funkcję" src="/images/docs/illustrations/i_render1.png" /> + <Illustration caption="Oblicza migawkę" src="/images/docs/illustrations/i_render2.png" /> + <Illustration caption="Aktualizuje drzewo DOM" src="/images/docs/illustrations/i_render3.png" /> </IllustrationBlock> -As a component's memory, state is not like a regular variable that disappears after your function returns. State actually "lives" in React itself--as if on a shelf!--outside of your function. When React calls your component, it gives you a snapshot of the state for that particular render. Your component returns a snapshot of the UI with a fresh set of props and event handlers in its JSX, all calculated **using the state values from that render!** +Będąc pamięcią komponentu, stan nie jest jak zwykła zmienna, która znika po zakończeniu działania funkcji. Stan, tak naprawdę, "żyje" w samym Reakcie (jakby był na półce!) poza twoją funkcją. Kiedy React wywołuje twój komponent, przekazuje ci migawkę stanu dla tego konkretnego renderowania. Twój komponent zwraca migawkę interfejsu użytkownika ze świeżym zestawem właściwości i procedur obsługi zdarzeń w swoim JSX, gdzie wszystko jest obliczone **przy użyciu wartości stanu z tego renderowania!** <IllustrationBlock sequential> - <Illustration caption="You tell React to update the state" src="/images/docs/illustrations/i_state-snapshot1.png" /> - <Illustration caption="React updates the state value" src="/images/docs/illustrations/i_state-snapshot2.png" /> - <Illustration caption="React passes a snapshot of the state value into the component" src="/images/docs/illustrations/i_state-snapshot3.png" /> + <Illustration caption="Informujesz Reacta o konieczności aktualizacji stanu" src="/images/docs/illustrations/i_state-snapshot1.png" /> + <Illustration caption="React aktualizuje wartość stanu" src="/images/docs/illustrations/i_state-snapshot2.png" /> + <Illustration caption="React przekazuje migawkę wartości stanu do komponentu" src="/images/docs/illustrations/i_state-snapshot3.png" /> </IllustrationBlock> -Here's a little experiment to show you how this works. In this example, you might expect that clicking the "+3" button would increment the counter three times because it calls `setNumber(number + 1)` three times. +Oto mały eksperyment, pokazujący jak to działa. W tym przykładzie można by się spodziewać, że kliknięcie przycisku "+3" zwiększy licznik trzykrotnie, ponieważ wywołuje on `setNumber(number + 1)` trzy razy. -See what happens when you click the "+3" button: +Zobacz, co się stanie po kliknięciu przycisku "+3": <Sandpack> @@ -127,9 +127,9 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; } </Sandpack> -Notice that `number` only increments once per click! +Zauważ, że `number` zwiększa się tylko o jeden za każdym kliknięciem! -**Setting state only changes it for the *next* render.** During the first render, `number` was `0`. This is why, in *that render's* `onClick` handler, the value of `number` is still `0` even after `setNumber(number + 1)` was called: +**Ustawienie stanu zmienia go dopiero w *następnym* renderowaniu.** Podczas pierwszego renderowania `number` miał wartość `0`. Dlatego w procedurze obsługi `onClick` dla *tego renderowania* wartość `number` nadal wynosi `0`, nawet po wywołaniu `setNumber(number + 1)`: ```js <button onClick={() => { @@ -139,18 +139,18 @@ Notice that `number` only increments once per click! }}>+3</button> ``` -Here is what this button's click handler tells React to do: +Oto co procedura obsługi kliknięcia tego przycisku każe zrobić Reactowi: -1. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`. - - React prepares to change `number` to `1` on the next render. -2. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`. - - React prepares to change `number` to `1` on the next render. -3. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`. - - React prepares to change `number` to `1` on the next render. +1. `setNumber(number + 1)`: `number` wynosi `0`, więc to inaczej `setNumber(0 + 1)`. + - React przygotowuje się do zmiany `number` na `1` przy następnym renderowaniu. +2. `setNumber(number + 1)`: `number` wynosi `0`, więc to inaczej `setNumber(0 + 1)`. + - React przygotowuje się do zmiany `number` na `1` przy następnym renderowaniu. +3. `setNumber(number + 1)`: `number` wynosi `0`, więc to inaczej `setNumber(0 + 1)`. + - React przygotowuje się do zmiany `number` na `1` przy następnym renderowaniu. -Even though you called `setNumber(number + 1)` three times, in *this render's* event handler `number` is always `0`, so you set the state to `1` three times. This is why, after your event handler finishes, React re-renders the component with `number` equal to `1` rather than `3`. +Mimo że wywołano `setNumber(number + 1)` trzy razy, w procedurze obsługi zdarzeń *tego renderowania* `number` zawsze wynosi `0`, więc trzy razy ustawiono stan na `1`. Dlatego po zakończeniu działania procedury obsługi zdarzeń, React ponownie renderuje komponent z `number` równym `1`, a nie `3`. -You can also visualize this by mentally substituting state variables with their values in your code. Since the `number` state variable is `0` for *this render*, its event handler looks like this: +Możesz to sobie również zwizualizować, podstawiając w myślach wartości zmiennych stanu w swoim kodzie. Ponieważ zmienna stanu `number` ma wartość `0` dla *tego renderowania*, jego procedura obsługi zdarzeń wygląda tak: ```js <button onClick={() => { @@ -159,8 +159,7 @@ You can also visualize this by mentally substituting state variables with their setNumber(0 + 1); }}>+3</button> ``` - -For the next render, `number` is `1`, so *that render's* click handler looks like this: +Dla następnego renderowania `number` wynosi `1`, więc procedura obsługi kliknięcia *tego renderowania* wygląda tak: ```js <button onClick={() => { @@ -170,11 +169,11 @@ For the next render, `number` is `1`, so *that render's* click handler looks lik }}>+3</button> ``` -This is why clicking the button again will set the counter to `2`, then to `3` on the next click, and so on. +Dlatego ponowne kliknięcie przycisku ustawi licznik na `2`, następnie na `3` przy kolejnym kliknięciu i tak dalej. -## State over time {/*state-over-time*/} +## Stan w czasie {/*state-over-time*/} -Well, that was fun. Try to guess what clicking this button will alert: +To było ciekawe. Spróbuj teraz zgadnąć, co wyświetli alert po kliknięciu tego przycisku: <Sandpack> @@ -203,14 +202,14 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; } </Sandpack> -If you use the substitution method from before, you can guess that the alert shows "0": +Jeśli zastosujesz metodę podstawiania wspomnianą wcześniej, możesz zgadnąć, że alert pokaże "0": ```js setNumber(0 + 5); alert(0); ``` -But what if you put a timer on the alert, so it only fires _after_ the component re-rendered? Would it say "0" or "5"? Have a guess! +A co, jeśli dodasz timer do alertu, tak aby wyświetlił się dopiero _po_ ponownym wyrenderowaniu komponentu? Pokaże on "0" czy "5"? Zgadnij! <Sandpack> @@ -241,7 +240,7 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; } </Sandpack> -Surprised? If you use the substitution method, you can see the "snapshot" of the state passed to the alert. +Zaskoczenie? Jeśli zastosujesz metodę podstawiania, zobaczysz "migawkę" stanu przekazaną do alertu. ```js setNumber(0 + 5); @@ -250,16 +249,16 @@ setTimeout(() => { }, 3000); ``` -The state stored in React may have changed by the time the alert runs, but it was scheduled using a snapshot of the state at the time the user interacted with it! +Stan przechowywany w Reakcie może zmienić się do czasu wyświetlenia alertu, ale alert ten został zaplanowany przy użyciu migawki stanu z momentu interakcji użytkownika! -**A state variable's value never changes within a render,** even if its event handler's code is asynchronous. Inside *that render's* `onClick`, the value of `number` continues to be `0` even after `setNumber(number + 5)` was called. Its value was "fixed" when React "took the snapshot" of the UI by calling your component. +**Wartość zmiennej stanu nigdy nie zmienia się w obrębie pojedynczego renderowania,** nawet jeśli kod jej procedury obsługi zdarzeń jest asynchroniczny. Wewnątrz metody `onClick` *tego renderowania*, wartość zmiennej `number` nadal wynosi `0`, nawet po wywołaniu `setNumber(number + 5)`. Jej wartość została "utrwalona" w momencie, gdy React "zrobił migawkę" interfejsu użytkownika poprzez wywołanie twojego komponentu. -Here is an example of how that makes your event handlers less prone to timing mistakes. Below is a form that sends a message with a five-second delay. Imagine this scenario: +Oto przykład pokazujący, jak to sprawia, że procedury obsługi zdarzeń są mniej podatne na błędy związane z czasem wykonania. Poniżej znajduje się formularz, który wysyła wiadomość z pięciosekundowym opóźnieniem. Wyobraź sobie taki scenariusz: -1. You press the "Send" button, sending "Hello" to Alice. -2. Before the five-second delay ends, you change the value of the "To" field to "Bob". +1. Naciskasz przycisk "Wyślij", aby wysłać wiadomość "Cześć" do Alice. +2. Zanim upłynie pięciosekundowe opóźnienie, zmieniasz wartość pola "Do" na "Bob". -What do you expect the `alert` to display? Would it display, "You said Hello to Alice"? Or would it display, "You said Hello to Bob"? Make a guess based on what you know, and then try it: +Jak myślisz, co wyświetli `alert`? Czy pokaże "Powiedziałeś/aś Cześć do Alice"? A może "Powiedziałeś/aś Cześć do Boba"? Spróbuj zgadnąć na podstawie tego, czego udało się ci dowiedzieć, a następnie sprawdź: <Sandpack> @@ -268,19 +267,19 @@ import { useState } from 'react'; export default function Form() { const [to, setTo] = useState('Alice'); - const [message, setMessage] = useState('Hello'); + const [message, setMessage] = useState('Cześć'); function handleSubmit(e) { e.preventDefault(); setTimeout(() => { - alert(`You said ${message} to ${to}`); + alert(`Powiedziałeś/aś ${message} do ${to}`); }, 5000); } return ( <form onSubmit={handleSubmit}> <label> - To:{' '} + Do:{' '} <select value={to} onChange={e => setTo(e.target.value)}> @@ -289,11 +288,11 @@ export default function Form() { </select> </label> <textarea - placeholder="Message" + placeholder="Wiadomość" value={message} onChange={e => setMessage(e.target.value)} /> - <button type="submit">Send</button> + <button type="submit">Wyślij</button> </form> ); } @@ -305,19 +304,19 @@ label, textarea { margin-bottom: 10px; display: block; } </Sandpack> -**React keeps the state values "fixed" within one render's event handlers.** You don't need to worry whether the state has changed while the code is running. +**React zachowuje wartości stanu jako "utrwalone" w procedurach obsługi zdarzeń dla danego renderowania.** Nie musisz się martwić, czy stan zmienił się podczas wykonywania kodu. -But what if you wanted to read the latest state before a re-render? You'll want to use a [state updater function](/learn/queueing-a-series-of-state-updates), covered on the next page! +A co, jeśli chcesz odczytać najnowszy stan przed ponownym renderowaniem? Wtedy będziesz potrzebować [funkcji aktualizującej stan](/learn/queueing-a-series-of-state-updates), którą omówimy na następnej stronie! <Recap> -* Setting state requests a new render. -* React stores state outside of your component, as if on a shelf. -* When you call `useState`, React gives you a snapshot of the state *for that render*. -* Variables and event handlers don't "survive" re-renders. Every render has its own event handlers. -* Every render (and functions inside it) will always "see" the snapshot of the state that React gave to *that* render. -* You can mentally substitute state in event handlers, similarly to how you think about the rendered JSX. -* Event handlers created in the past have the state values from the render in which they were created. +* Ustawienie stanu żąda nowego renderowania. +* React przechowuje stan poza komponentem, jakby na półce. +* Kiedy wywołujesz `useState`, React daje ci migawkę stanu *dla tego renderowania*. +* Zmienne i procedury obsługi zdarzeń nie są w stanie "przetrwać" ponownego renderowania. Każde renderowanie ma własne procedury obsługi. +* Każde renderowanie (i funkcje wewnątrz niego) zawsze "widzą" migawkę stanu, którą React przekazał *temu* renderowaniu. +* Możesz w myślach podstawiać stan w procedurach obsługi zdarzeń, podobnie jak myślisz o wyrenderowanym JSX. +* Procedury obsługi zdarzeń utworzone w przeszłości mają wartości stanu z renderowania, w którym zostały utworzone. </Recap> @@ -325,9 +324,9 @@ But what if you wanted to read the latest state before a re-render? You'll want <Challenges> -#### Implement a traffic light {/*implement-a-traffic-light*/} +#### Zaimplementuj światła uliczne {/*implement-a-traffic-light*/} -Here is a crosswalk light component that toggles when the button is pressed: +Oto komponent świateł na przejściu dla pieszych, który przełącza się po naciśnięciu przycisku: <Sandpack> @@ -344,12 +343,12 @@ export default function TrafficLight() { return ( <> <button onClick={handleClick}> - Change to {walk ? 'Stop' : 'Walk'} + Zmień na {walk ? 'Stój' : 'Idź'} </button> <h1 style={{ color: walk ? 'darkgreen' : 'darkred' }}> - {walk ? 'Walk' : 'Stop'} + {walk ? 'Idź' : 'Stój'} </h1> </> ); @@ -362,13 +361,13 @@ h1 { margin-top: 20px; } </Sandpack> -Add an `alert` to the click handler. When the light is green and says "Walk", clicking the button should say "Stop is next". When the light is red and says "Stop", clicking the button should say "Walk is next". +Dodaj `alert` do procedury obsługi kliknięcia. Kiedy światło jest zielone i wyświetla "Idź", kliknięcie przycisku powinno pokazać "Następnie będzie Stój". Kiedy światło jest czerwone i wyświetla "Stój", kliknięcie przycisku powinno pokazać "Następnie będzie Idź". -Does it make a difference whether you put the `alert` before or after the `setWalk` call? +Czy ma znaczenie, czy umieścisz `alert` przed czy po wywołaniu `setWalk`? <Solution> -Your `alert` should look like this: +Twój `alert` powinien wyglądać tak: <Sandpack> @@ -380,18 +379,18 @@ export default function TrafficLight() { function handleClick() { setWalk(!walk); - alert(walk ? 'Stop is next' : 'Walk is next'); + alert(walk ? 'Następnie będzie Stój' : 'Następnie będzie Idź'); } return ( <> <button onClick={handleClick}> - Change to {walk ? 'Stop' : 'Walk'} + Zmień na {walk ? 'Stój' : 'Idź'} </button> <h1 style={{ color: walk ? 'darkgreen' : 'darkred' }}> - {walk ? 'Walk' : 'Stop'} + {walk ? 'Idź' : 'Stój'} </h1> </> ); @@ -404,32 +403,35 @@ h1 { margin-top: 20px; } </Sandpack> -Whether you put it before or after the `setWalk` call makes no difference. That render's value of `walk` is fixed. Calling `setWalk` will only change it for the *next* render, but will not affect the event handler from the previous render. +Nie ma znaczenia, czy umieścisz alert przed czy po wywołaniu `setWalk`. Wartość `walk` dla tego renderowania jest utrwalona. Wywołanie `setWalk` zmieni ją tylko dla *następnego* renderowania, ale nie wpłynie na procedurę obsługi zdarzeń z poprzedniego renderowania. -This line might seem counter-intuitive at first: +Ta linia może początkowo wydawać się nieintuicyjna: ```js -alert(walk ? 'Stop is next' : 'Walk is next'); +alert(walk ? 'Następnie będzie Stój' : 'Następnie będzie Idź'); ``` -But it makes sense if you read it as: "If the traffic light shows 'Walk now', the message should say 'Stop is next.'" The `walk` variable inside your event handler matches that render's value of `walk` and does not change. +Ale ma ona sens, jeśli przeczytasz ją tak: "Jeśli sygnalizator pokazuje 'Idź', komunikat powinien brzmieć 'Następnie będzie Stój'". Zmienna `walk` wewnątrz procedury obsługi zdarzeń odpowiada wartości `walk` z tego renderowania i nie zmienia się. -You can verify that this is correct by applying the substitution method. When `walk` is `true`, you get: +Możesz to zweryfikować, stosując metodę podstawiania. Kiedy `walk` ma wartość `true`, otrzymujesz: ```js <button onClick={() => { setWalk(false); - alert('Stop is next'); + alert('Następnie będzie Stój'); }}> - Change to Stop + Zmień na Stój </button> <h1 style={{color: 'darkgreen'}}> - Walk + Idź </h1> ``` -So clicking "Change to Stop" queues a render with `walk` set to `false`, and alerts "Stop is next". +Więc kliknięcie "Zmień na Stój" dodaje do kolejki renderowanie z `walk` ustawionym na `false` i wyświetla alert "Następnie będzie Stój". </Solution> </Challenges> + + +[def]: /learn/queueing-a-series-of-state-updates \ No newline at end of file diff --git a/src/content/learn/synchronizing-with-effects.md b/src/content/learn/synchronizing-with-effects.md index f1aa98438..115075161 100644 --- a/src/content/learn/synchronizing-with-effects.md +++ b/src/content/learn/synchronizing-with-effects.md @@ -45,7 +45,7 @@ Here and later in this text, capitalized "Effect" refers to the React-specific d To write an Effect, follow these three steps: -1. **Declare an Effect.** By default, your Effect will run after every render. +1. **Declare an Effect.** By default, your Effect will run after every [commit](/learn/render-and-commit). 2. **Specify the Effect dependencies.** Most Effects should only re-run *when needed* rather than after every render. For example, a fade-in animation should only trigger when a component appears. Connecting and disconnecting to a chat room should only happen when the component appears and disappears, or when the chat room changes. You will learn how to control this by specifying *dependencies.* 3. **Add cleanup if needed.** Some Effects need to specify how to stop, undo, or clean up whatever they were doing. For example, "connect" needs "disconnect", "subscribe" needs "unsubscribe", and "fetch" needs either "cancel" or "ignore". You will learn how to do this by returning a *cleanup function*. @@ -598,9 +598,36 @@ Usually, the answer is to implement the cleanup function. The cleanup function Most of the Effects you'll write will fit into one of the common patterns below. +<Pitfall> + +#### Don't use refs to prevent Effects from firing {/*dont-use-refs-to-prevent-effects-from-firing*/} + +A common pitfall for preventing Effects firing twice in development is to use a `ref` to prevent the Effect from running more than once. For example, you could "fix" the above bug with a `useRef`: + +```js {1,3-4} + const connectionRef = useRef(null); + useEffect(() => { + // 🚩 This wont fix the bug!!! + if (!connectionRef.current) { + connectionRef.current = createConnection(); + connectionRef.current.connect(); + } + }, []); +``` + +This makes it so you only see `"✅ Connecting..."` once in development, but it doesn't fix the bug. + +When the user navigates away, the connection still isn't closed and when they navigate back, a new connection is created. As the user navigates across the app, the connections would keep piling up, the same as it would before the "fix". + +To fix the bug, it is not enough to just make the Effect run once. The effect needs to work after re-mounting, which means the connection needs to be cleaned up like in the solution above. + +See the examples below for how to handle common patterns. + +</Pitfall> + ### Controlling non-React widgets {/*controlling-non-react-widgets*/} -Sometimes you need to add UI widgets that aren't written to React. For example, let's say you're adding a map component to your page. It has a `setZoomLevel()` method, and you'd like to keep the zoom level in sync with a `zoomLevel` state variable in your React code. Your Effect would look similar to this: +Sometimes you need to add UI widgets that aren't written in React. For example, let's say you're adding a map component to your page. It has a `setZoomLevel()` method, and you'd like to keep the zoom level in sync with a `zoomLevel` state variable in your React code. Your Effect would look similar to this: ```js useEffect(() => { @@ -1573,7 +1600,7 @@ Each render's Effect has its own `ignore` variable. Initially, the `ignore` vari - Fetching `'Bob'` completes - The Effect from the `'Bob'` render **does not do anything because its `ignore` flag was set to `true`** -In addition to ignoring the result of an outdated API call, you can also use [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to cancel the requests that are no longer needed. However, by itself this is not enough to protect against race conditions. More asynchronous steps could be chained after the fetch, so using an explicit flag like `ignore` is the most reliable way to fix this type of problems. +In addition to ignoring the result of an outdated API call, you can also use [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to cancel the requests that are no longer needed. However, by itself this is not enough to protect against race conditions. More asynchronous steps could be chained after the fetch, so using an explicit flag like `ignore` is the most reliable way to fix this type of problem. </Solution> diff --git a/src/content/learn/thinking-in-react.md b/src/content/learn/thinking-in-react.md index 3ac87f89e..3028d079b 100644 --- a/src/content/learn/thinking-in-react.md +++ b/src/content/learn/thinking-in-react.md @@ -268,8 +268,8 @@ Zastosujmy na tym stanie poznaną przez nas strategię: 1. **Zidentyfikuj komponenty, które korzystają z tego stanu:** * `ProductTable` musi filtrować produkty na podstawie tego stanu (tekstu wyszukiwarki i wartości pola wyboru). * `SearchBar` musi wyświetlać ten stan (tekst wyszukiwarki i wartość pola wyboru). -1. **Znajdź ich wspólnego rodzica:** Pierwszym rodzicem wspólnym dla obydwu komponentów jest `FilterableProductTable`. -2. **Zdecyduj, gdzie stan powinien być umieszczony**: Będziemy trzymać go w `FilterableProductTable`. +2. **Znajdź ich wspólnego rodzica:** Pierwszym rodzicem wspólnym dla obydwu komponentów jest `FilterableProductTable`. +3. **Zdecyduj, gdzie stan powinien być umieszczony**: Będziemy trzymać go w `FilterableProductTable`. Tak więc wartości stanu będą przechowywane w komponencie `FilterableProductTable`. diff --git a/src/content/learn/tutorial-tic-tac-toe.md b/src/content/learn/tutorial-tic-tac-toe.md index d37791456..6487e8007 100644 --- a/src/content/learn/tutorial-tic-tac-toe.md +++ b/src/content/learn/tutorial-tic-tac-toe.md @@ -1133,7 +1133,7 @@ Calling the `setSquares` function lets React know the state of the component has <Note> -JavaScript supports [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) which means an inner function (e.g. `handleClick`) has access to variables and functions defined in a outer function (e.g. `Board`). The `handleClick` function can read the `squares` state and call the `setSquares` method because they are both defined inside of the `Board` function. +JavaScript supports [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) which means an inner function (e.g. `handleClick`) has access to variables and functions defined in an outer function (e.g. `Board`). The `handleClick` function can read the `squares` state and call the `setSquares` method because they are both defined inside of the `Board` function. </Note> @@ -2915,4 +2915,4 @@ If you have extra time or want to practice your new React skills, here are some 1. When someone wins, highlight the three squares that caused the win (and when no one wins, display a message about the result being a draw). 1. Display the location for each move in the format (row, col) in the move history list. -Throughout this tutorial, you've touched on React concepts including elements, components, props, and state. Now that you've seen how these concepts work when building a game, check out [Thinking in React](/learn/thinking-in-react) to see how the same React concepts work when build an app's UI. +Throughout this tutorial, you've touched on React concepts including elements, components, props, and state. Now that you've seen how these concepts work when building a game, check out [Thinking in React](/learn/thinking-in-react) to see how the same React concepts work when building an app's UI. diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 034ac0d46..7edf8eb6e 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -22,7 +22,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out All [production-grade React frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) offer support for using TypeScript. Follow the framework specific guide for installation: -- [Next.js](https://nextjs.org/docs/pages/building-your-application/configuring/typescript) +- [Next.js](https://nextjs.org/docs/app/building-your-application/configuring/typescript) - [Remix](https://remix.run/docs/en/1.19.2/guides/typescript) - [Gatsby](https://www.gatsbyjs.com/docs/how-to/custom-configuration/typescript/) - [Expo](https://docs.expo.dev/guides/typescript/) @@ -137,7 +137,7 @@ The [`useState` Hook](/reference/react/useState) will re-use the value passed in const [enabled, setEnabled] = useState(false); ``` -Will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call: +This will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call: ```ts // Explicitly set the type to "boolean" @@ -435,7 +435,7 @@ interface ModalRendererProps { Note, that you cannot use TypeScript to describe that the children are a certain type of JSX elements, so you cannot use the type-system to describe a component which only accepts `<li>` children. -You can see all an example of both `React.ReactNode` and `React.ReactElement` with the type-checker in [this TypeScript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheQgA). +You can see an example of both `React.ReactNode` and `React.ReactElement` with the type-checker in [this TypeScript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheQgA). ### Style Props {/*typing-style-props*/} @@ -456,7 +456,7 @@ We recommend the following resources: - [The TypeScript handbook](https://www.typescriptlang.org/docs/handbook/) is the official documentation for TypeScript, and covers most key language features. - - [The TypeScript release notes](https://devblogs.microsoft.com/typescript/) covers a each new features in-depth. + - [The TypeScript release notes](https://devblogs.microsoft.com/typescript/) cover new features in depth. - [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/) is a community-maintained cheatsheet for using TypeScript with React, covering a lot of useful edge cases and providing more breadth than this document. diff --git a/src/content/learn/updating-objects-in-state.md b/src/content/learn/updating-objects-in-state.md index 13459e6ba..3f9cb890d 100644 --- a/src/content/learn/updating-objects-in-state.md +++ b/src/content/learn/updating-objects-in-state.md @@ -57,6 +57,7 @@ This example holds an object in state to represent the current pointer position. ```js import { useState } from 'react'; + export default function MovingDot() { const [position, setPosition] = useState({ x: 0, @@ -127,6 +128,7 @@ Notice how the red dot now follows your pointer when you touch or hover over the ```js import { useState } from 'react'; + export default function MovingDot() { const [position, setPosition] = useState({ x: 0, @@ -377,7 +379,7 @@ Note that the `...` spread syntax is "shallow"--it only copies things one level #### Using a single event handler for multiple fields {/*using-a-single-event-handler-for-multiple-fields*/} -You can also use the `[` and `]` braces inside your object definition to specify a property with dynamic name. Here is the same example, but with a single event handler instead of three different ones: +You can also use the `[` and `]` braces inside your object definition to specify a property with a dynamic name. Here is the same example, but with a single event handler instead of three different ones: <Sandpack> diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index 66cdc3117..a009793ab 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -408,9 +408,9 @@ function Game() { There are two problems with this code. -One problem is that it is very inefficient: the component (and its children) have to re-render between each `set` call in the chain. In the example above, in the worst case (`setCard` → render → `setGoldCardCount` → render → `setRound` → render → `setIsGameOver` → render) there are three unnecessary re-renders of the tree below. +The first problem is that it is very inefficient: the component (and its children) have to re-render between each `set` call in the chain. In the example above, in the worst case (`setCard` → render → `setGoldCardCount` → render → `setRound` → render → `setIsGameOver` → render) there are three unnecessary re-renders of the tree below. -Even if it weren't slow, as your code evolves, you will run into cases where the "chain" you wrote doesn't fit the new requirements. Imagine you are adding a way to step through the history of the game moves. You'd do it by updating each state variable to a value from the past. However, setting the `card` state to a value from the past would trigger the Effect chain again and change the data you're showing. Such code is often rigid and fragile. +The second problem is that even if it weren't slow, as your code evolves, you will run into cases where the "chain" you wrote doesn't fit the new requirements. Imagine you are adding a way to step through the history of the game moves. You'd do it by updating each state variable to a value from the past. However, setting the `card` state to a value from the past would trigger the Effect chain again and change the data you're showing. Such code is often rigid and fragile. In this case, it's better to calculate what you can during rendering, and adjust the state in the event handler: diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index afddb4177..a2bef6bf2 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -45,7 +45,9 @@ An app fully built with React will usually only have one `createRoot` call for i * **optional** `options`: An object with options for this React root. - * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. + * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`. + * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown, and an `errorInfo` object containing the `componentStack`. + * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with an `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`. * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page. #### Returns {/*returns*/} @@ -342,6 +344,774 @@ export default function App({counter}) { It is uncommon to call `render` multiple times. Usually, your components will [update state](/reference/react/useState) instead. +### Show a dialog for uncaught errors {/*show-a-dialog-for-uncaught-errors*/} + +By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional `onUncaughtError` root option: + +```js [[1, 6, "onUncaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack"]] +import { createRoot } from 'react-dom/client'; + +const root = createRoot( + document.getElementById('root'), + { + onUncaughtError: (error, errorInfo) => { + console.error( + 'Uncaught error', + error, + errorInfo.componentStack + ); + } + } +); +root.render(<App />); +``` + +The <CodeStep step={1}>onUncaughtError</CodeStep> option is a function called with two arguments: + +1. The <CodeStep step={2}>error</CodeStep> that was thrown. +2. An <CodeStep step={3}>errorInfo</CodeStep> object that contains the <CodeStep step={4}>componentStack</CodeStep> of the error. + +You can use the `onUncaughtError` root option to display error dialogs: + +<Sandpack> + +```html index.html hidden +<!DOCTYPE html> +<html> +<head> + <title>My app + + + + + +
    + + +``` + +```css src/styles.css active +label, button { display: block; margin-bottom: 20px; } +html, body { min-height: 300px; } + +#error-dialog { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: white; + padding: 15px; + opacity: 0.9; + text-wrap: wrap; + overflow: scroll; +} + +.text-red { + color: red; +} + +.-mb-20 { + margin-bottom: -20px; +} + +.mb-0 { + margin-bottom: 0; +} + +.mb-10 { + margin-bottom: 10px; +} + +pre { + text-wrap: wrap; +} + +pre.nowrap { + text-wrap: nowrap; +} + +.hidden { + display: none; +} +``` + +```js src/reportError.js hidden +function reportError({ title, error, componentStack, dismissable }) { + const errorDialog = document.getElementById("error-dialog"); + const errorTitle = document.getElementById("error-title"); + const errorMessage = document.getElementById("error-message"); + const errorBody = document.getElementById("error-body"); + const errorComponentStack = document.getElementById("error-component-stack"); + const errorStack = document.getElementById("error-stack"); + const errorClose = document.getElementById("error-close"); + const errorCause = document.getElementById("error-cause"); + const errorCauseMessage = document.getElementById("error-cause-message"); + const errorCauseStack = document.getElementById("error-cause-stack"); + const errorNotDismissible = document.getElementById("error-not-dismissible"); + + // Set the title + errorTitle.innerText = title; + + // Display error message and body + const [heading, body] = error.message.split(/\n(.*)/s); + errorMessage.innerText = heading; + if (body) { + errorBody.innerText = body; + } else { + errorBody.innerText = ''; + } + + // Display component stack + errorComponentStack.innerText = componentStack; + + // Display the call stack + // Since we already displayed the message, strip it, and the first Error: line. + errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; + + // Display the cause, if available + if (error.cause) { + errorCauseMessage.innerText = error.cause.message; + errorCauseStack.innerText = error.cause.stack; + errorCause.classList.remove('hidden'); + } else { + errorCause.classList.add('hidden'); + } + // Display the close button, if dismissible + if (dismissable) { + errorNotDismissible.classList.add('hidden'); + errorClose.classList.remove("hidden"); + } else { + errorNotDismissible.classList.remove('hidden'); + errorClose.classList.add("hidden"); + } + + // Show the dialog + errorDialog.classList.remove("hidden"); +} + +export function reportCaughtError({error, cause, componentStack}) { + reportError({ title: "Caught Error", error, componentStack, dismissable: true}); +} + +export function reportUncaughtError({error, cause, componentStack}) { + reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); +} + +export function reportRecoverableError({error, cause, componentStack}) { + reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +} +``` + +```js src/index.js active +import { createRoot } from "react-dom/client"; +import App from "./App.js"; +import {reportUncaughtError} from "./reportError"; +import "./styles.css"; + +const container = document.getElementById("root"); +const root = createRoot(container, { + onUncaughtError: (error, errorInfo) => { + if (error.message !== 'Known error') { + reportUncaughtError({ + error, + componentStack: errorInfo.componentStack + }); + } + } +}); +root.render(); +``` + +```js src/App.js +import { useState } from 'react'; + +export default function App() { + const [throwError, setThrowError] = useState(false); + + if (throwError) { + foo.bar = 'baz'; + } + + return ( +
    + This error shows the error dialog: + +
    + ); +} +``` + + + + +### Displaying Error Boundary errors {/*displaying-error-boundary-errors*/} + +By default, React will log all errors caught by an Error Boundary to `console.error`. To override this behavior, you can provide the optional `onCaughtError` root option to handle errors caught by an [Error Boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary): + +```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack"]] +import { createRoot } from 'react-dom/client'; + +const root = createRoot( + document.getElementById('root'), + { + onCaughtError: (error, errorInfo) => { + console.error( + 'Caught error', + error, + errorInfo.componentStack + ); + } + } +); +root.render(); +``` + +The onCaughtError option is a function called with two arguments: + +1. The error that was caught by the boundary. +2. An errorInfo object that contains the componentStack of the error. + +You can use the `onCaughtError` root option to display error dialogs or filter known errors from logging: + + + +```html index.html hidden + + + + My app + + + + + +
    + + +``` + +```css src/styles.css active +label, button { display: block; margin-bottom: 20px; } +html, body { min-height: 300px; } + +#error-dialog { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: white; + padding: 15px; + opacity: 0.9; + text-wrap: wrap; + overflow: scroll; +} + +.text-red { + color: red; +} + +.-mb-20 { + margin-bottom: -20px; +} + +.mb-0 { + margin-bottom: 0; +} + +.mb-10 { + margin-bottom: 10px; +} + +pre { + text-wrap: wrap; +} + +pre.nowrap { + text-wrap: nowrap; +} + +.hidden { + display: none; +} +``` + +```js src/reportError.js hidden +function reportError({ title, error, componentStack, dismissable }) { + const errorDialog = document.getElementById("error-dialog"); + const errorTitle = document.getElementById("error-title"); + const errorMessage = document.getElementById("error-message"); + const errorBody = document.getElementById("error-body"); + const errorComponentStack = document.getElementById("error-component-stack"); + const errorStack = document.getElementById("error-stack"); + const errorClose = document.getElementById("error-close"); + const errorCause = document.getElementById("error-cause"); + const errorCauseMessage = document.getElementById("error-cause-message"); + const errorCauseStack = document.getElementById("error-cause-stack"); + const errorNotDismissible = document.getElementById("error-not-dismissible"); + + // Set the title + errorTitle.innerText = title; + + // Display error message and body + const [heading, body] = error.message.split(/\n(.*)/s); + errorMessage.innerText = heading; + if (body) { + errorBody.innerText = body; + } else { + errorBody.innerText = ''; + } + + // Display component stack + errorComponentStack.innerText = componentStack; + + // Display the call stack + // Since we already displayed the message, strip it, and the first Error: line. + errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; + + // Display the cause, if available + if (error.cause) { + errorCauseMessage.innerText = error.cause.message; + errorCauseStack.innerText = error.cause.stack; + errorCause.classList.remove('hidden'); + } else { + errorCause.classList.add('hidden'); + } + // Display the close button, if dismissible + if (dismissable) { + errorNotDismissible.classList.add('hidden'); + errorClose.classList.remove("hidden"); + } else { + errorNotDismissible.classList.remove('hidden'); + errorClose.classList.add("hidden"); + } + + // Show the dialog + errorDialog.classList.remove("hidden"); +} + +export function reportCaughtError({error, cause, componentStack}) { + reportError({ title: "Caught Error", error, componentStack, dismissable: true}); +} + +export function reportUncaughtError({error, cause, componentStack}) { + reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); +} + +export function reportRecoverableError({error, cause, componentStack}) { + reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +} +``` + +```js src/index.js active +import { createRoot } from "react-dom/client"; +import App from "./App.js"; +import {reportCaughtError} from "./reportError"; +import "./styles.css"; + +const container = document.getElementById("root"); +const root = createRoot(container, { + onCaughtError: (error, errorInfo) => { + if (error.message !== 'Known error') { + reportCaughtError({ + error, + componentStack: errorInfo.componentStack, + }); + } + } +}); +root.render(); +``` + +```js src/App.js +import { useState } from 'react'; +import { ErrorBoundary } from "react-error-boundary"; + +export default function App() { + const [error, setError] = useState(null); + + function handleUnknown() { + setError("unknown"); + } + + function handleKnown() { + setError("known"); + } + + return ( + <> + { + setError(null); + }} + > + {error != null && } + This error will not show the error dialog: + + This error will show the error dialog: + + + + + ); +} + +function fallbackRender({ resetErrorBoundary }) { + return ( +
    +

    Error Boundary

    +

    Something went wrong.

    + +
    + ); +} + +function Throw({error}) { + if (error === "known") { + throw new Error('Known error') + } else { + foo.bar = 'baz'; + } +} +``` + +```json package.json hidden +{ + "dependencies": { + "react": "19.0.0-rc-3edc000d-20240926", + "react-dom": "19.0.0-rc-3edc000d-20240926", + "react-scripts": "^5.0.0", + "react-error-boundary": "4.0.3" + }, + "main": "/index.js" +} +``` + +
    + +### Displaying a dialog for recoverable errors {/*displaying-a-dialog-for-recoverable-errors*/} + +React may automatically render a component a second time to attempt to recover from an error thrown in render. If successful, React will log a recoverable error to the console to notify the developer. To override this behavior, you can provide the optional `onRecoverableError` root option: + +```js [[1, 6, "onRecoverableError"], [2, 6, "error", 1], [3, 10, "error.cause"], [4, 6, "errorInfo"], [5, 11, "componentStack"]] +import { createRoot } from 'react-dom/client'; + +const root = createRoot( + document.getElementById('root'), + { + onRecoverableError: (error, errorInfo) => { + console.error( + 'Recoverable error', + error, + error.cause, + errorInfo.componentStack, + ); + } + } +); +root.render(); +``` + +The onRecoverableError option is a function called with two arguments: + +1. The error that React throws. Some errors may include the original cause as error.cause. +2. An errorInfo object that contains the componentStack of the error. + +You can use the `onRecoverableError` root option to display error dialogs: + + + +```html index.html hidden + + + + My app + + + + + +
    + + +``` + +```css src/styles.css active +label, button { display: block; margin-bottom: 20px; } +html, body { min-height: 300px; } + +#error-dialog { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: white; + padding: 15px; + opacity: 0.9; + text-wrap: wrap; + overflow: scroll; +} + +.text-red { + color: red; +} + +.-mb-20 { + margin-bottom: -20px; +} + +.mb-0 { + margin-bottom: 0; +} + +.mb-10 { + margin-bottom: 10px; +} + +pre { + text-wrap: wrap; +} + +pre.nowrap { + text-wrap: nowrap; +} + +.hidden { + display: none; +} +``` + +```js src/reportError.js hidden +function reportError({ title, error, componentStack, dismissable }) { + const errorDialog = document.getElementById("error-dialog"); + const errorTitle = document.getElementById("error-title"); + const errorMessage = document.getElementById("error-message"); + const errorBody = document.getElementById("error-body"); + const errorComponentStack = document.getElementById("error-component-stack"); + const errorStack = document.getElementById("error-stack"); + const errorClose = document.getElementById("error-close"); + const errorCause = document.getElementById("error-cause"); + const errorCauseMessage = document.getElementById("error-cause-message"); + const errorCauseStack = document.getElementById("error-cause-stack"); + const errorNotDismissible = document.getElementById("error-not-dismissible"); + + // Set the title + errorTitle.innerText = title; + + // Display error message and body + const [heading, body] = error.message.split(/\n(.*)/s); + errorMessage.innerText = heading; + if (body) { + errorBody.innerText = body; + } else { + errorBody.innerText = ''; + } + + // Display component stack + errorComponentStack.innerText = componentStack; + + // Display the call stack + // Since we already displayed the message, strip it, and the first Error: line. + errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; + + // Display the cause, if available + if (error.cause) { + errorCauseMessage.innerText = error.cause.message; + errorCauseStack.innerText = error.cause.stack; + errorCause.classList.remove('hidden'); + } else { + errorCause.classList.add('hidden'); + } + // Display the close button, if dismissible + if (dismissable) { + errorNotDismissible.classList.add('hidden'); + errorClose.classList.remove("hidden"); + } else { + errorNotDismissible.classList.remove('hidden'); + errorClose.classList.add("hidden"); + } + + // Show the dialog + errorDialog.classList.remove("hidden"); +} + +export function reportCaughtError({error, cause, componentStack}) { + reportError({ title: "Caught Error", error, componentStack, dismissable: true}); +} + +export function reportUncaughtError({error, cause, componentStack}) { + reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); +} + +export function reportRecoverableError({error, cause, componentStack}) { + reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +} +``` + +```js src/index.js active +import { createRoot } from "react-dom/client"; +import App from "./App.js"; +import {reportRecoverableError} from "./reportError"; +import "./styles.css"; + +const container = document.getElementById("root"); +const root = createRoot(container, { + onRecoverableError: (error, errorInfo) => { + reportRecoverableError({ + error, + cause: error.cause, + componentStack: errorInfo.componentStack, + }); + } +}); +root.render(); +``` + +```js src/App.js +import { useState } from 'react'; +import { ErrorBoundary } from "react-error-boundary"; + +// 🚩 Bug: Never do this. This will force an error. +let errorThrown = false; +export default function App() { + return ( + <> + + {!errorThrown && } +

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

    +

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

    +
    + + + ); +} + +function fallbackRender() { + return ( +
    +

    Error Boundary

    +

    Something went wrong.

    +
    + ); +} + +function Throw({error}) { + // Simulate an external value changing during concurrent render. + errorThrown = true; + foo.bar = 'baz'; +} +``` + +```json package.json hidden +{ + "dependencies": { + "react": "19.0.0-rc-3edc000d-20240926", + "react-dom": "19.0.0-rc-3edc000d-20240926", + "react-scripts": "^5.0.0", + "react-error-boundary": "4.0.3" + }, + "main": "/index.js" +} +``` + +
    + + --- ## Troubleshooting {/*troubleshooting*/} @@ -361,6 +1131,28 @@ Until you do that, nothing is displayed. --- +### I'm getting an error: "You passed a second argument to root.render" {/*im-getting-an-error-you-passed-a-second-argument-to-root-render*/} + +A common mistake is to pass the options for `createRoot` to `root.render(...)`: + + + +Warning: You passed a second argument to root.render(...) but it only accepts one argument. + + + +To fix, pass the root options to `createRoot(...)`, not `root.render(...)`: +```js {2,5} +// 🚩 Wrong: root.render only takes one argument. +root.render(App, {onUncaughtError}); + +// ✅ Correct: pass options to createRoot. +const root = createRoot(container, {onUncaughtError}); +root.render(); +``` + +--- + ### I'm getting an error: "Target container is not a DOM element" {/*im-getting-an-error-target-container-is-not-a-dom-element*/} This error means that whatever you're passing to `createRoot` is not a DOM node. diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index c137cdda9..c54b6fe11 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -41,7 +41,9 @@ React will attach to the HTML that exists inside the `domNode`, and take over ma * **optional** `options`: An object with options for this React root. - * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. + * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`. + * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown and an `errorInfo` object containing the `componentStack`. + * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with the `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`. * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix as used on the server. @@ -371,3 +373,803 @@ export default function App({counter}) { It is uncommon to call [`root.render`](#root-render) on a hydrated root. Usually, you'll [update state](/reference/react/useState) inside one of the components instead. + +### Show a dialog for uncaught errors {/*show-a-dialog-for-uncaught-errors*/} + +By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional `onUncaughtError` root option: + +```js [[1, 7, "onUncaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]] +import { hydrateRoot } from 'react-dom/client'; + +const root = hydrateRoot( + document.getElementById('root'), + , + { + onUncaughtError: (error, errorInfo) => { + console.error( + 'Uncaught error', + error, + errorInfo.componentStack + ); + } + } +); +root.render(); +``` + +The onUncaughtError option is a function called with two arguments: + +1. The error that was thrown. +2. An errorInfo object that contains the componentStack of the error. + +You can use the `onUncaughtError` root option to display error dialogs: + + + +```html index.html hidden + + + + My app + + + + + +
    This error shows the error dialog:
    + + +``` + +```css src/styles.css active +label, button { display: block; margin-bottom: 20px; } +html, body { min-height: 300px; } + +#error-dialog { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: white; + padding: 15px; + opacity: 0.9; + text-wrap: wrap; + overflow: scroll; +} + +.text-red { + color: red; +} + +.-mb-20 { + margin-bottom: -20px; +} + +.mb-0 { + margin-bottom: 0; +} + +.mb-10 { + margin-bottom: 10px; +} + +pre { + text-wrap: wrap; +} + +pre.nowrap { + text-wrap: nowrap; +} + +.hidden { + display: none; +} +``` + +```js src/reportError.js hidden +function reportError({ title, error, componentStack, dismissable }) { + const errorDialog = document.getElementById("error-dialog"); + const errorTitle = document.getElementById("error-title"); + const errorMessage = document.getElementById("error-message"); + const errorBody = document.getElementById("error-body"); + const errorComponentStack = document.getElementById("error-component-stack"); + const errorStack = document.getElementById("error-stack"); + const errorClose = document.getElementById("error-close"); + const errorCause = document.getElementById("error-cause"); + const errorCauseMessage = document.getElementById("error-cause-message"); + const errorCauseStack = document.getElementById("error-cause-stack"); + const errorNotDismissible = document.getElementById("error-not-dismissible"); + + // Set the title + errorTitle.innerText = title; + + // Display error message and body + const [heading, body] = error.message.split(/\n(.*)/s); + errorMessage.innerText = heading; + if (body) { + errorBody.innerText = body; + } else { + errorBody.innerText = ''; + } + + // Display component stack + errorComponentStack.innerText = componentStack; + + // Display the call stack + // Since we already displayed the message, strip it, and the first Error: line. + errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; + + // Display the cause, if available + if (error.cause) { + errorCauseMessage.innerText = error.cause.message; + errorCauseStack.innerText = error.cause.stack; + errorCause.classList.remove('hidden'); + } else { + errorCause.classList.add('hidden'); + } + // Display the close button, if dismissible + if (dismissable) { + errorNotDismissible.classList.add('hidden'); + errorClose.classList.remove("hidden"); + } else { + errorNotDismissible.classList.remove('hidden'); + errorClose.classList.add("hidden"); + } + + // Show the dialog + errorDialog.classList.remove("hidden"); +} + +export function reportCaughtError({error, cause, componentStack}) { + reportError({ title: "Caught Error", error, componentStack, dismissable: true}); +} + +export function reportUncaughtError({error, cause, componentStack}) { + reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); +} + +export function reportRecoverableError({error, cause, componentStack}) { + reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +} +``` + +```js src/index.js active +import { hydrateRoot } from "react-dom/client"; +import App from "./App.js"; +import {reportUncaughtError} from "./reportError"; +import "./styles.css"; +import {renderToString} from 'react-dom/server'; + +const container = document.getElementById("root"); +const root = hydrateRoot(container, , { + onUncaughtError: (error, errorInfo) => { + if (error.message !== 'Known error') { + reportUncaughtError({ + error, + componentStack: errorInfo.componentStack + }); + } + } +}); +``` + +```js src/App.js +import { useState } from 'react'; + +export default function App() { + const [throwError, setThrowError] = useState(false); + + if (throwError) { + foo.bar = 'baz'; + } + + return ( +
    + This error shows the error dialog: + +
    + ); +} +``` + +
    + + +### Displaying Error Boundary errors {/*displaying-error-boundary-errors*/} + +By default, React will log all errors caught by an Error Boundary to `console.error`. To override this behavior, you can provide the optional `onCaughtError` root option for errors caught by an [Error Boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary): + +```js [[1, 7, "onCaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]] +import { hydrateRoot } from 'react-dom/client'; + +const root = hydrateRoot( + document.getElementById('root'), + , + { + onCaughtError: (error, errorInfo) => { + console.error( + 'Caught error', + error, + errorInfo.componentStack + ); + } + } +); +root.render(); +``` + +The onCaughtError option is a function called with two arguments: + +1. The error that was caught by the boundary. +2. An errorInfo object that contains the componentStack of the error. + +You can use the `onCaughtError` root option to display error dialogs or filter known errors from logging: + + + +```html index.html hidden + + + + My app + + + + + +
    This error will not show the error dialog:This error will show the error dialog:
    + + +``` + +```css src/styles.css active +label, button { display: block; margin-bottom: 20px; } +html, body { min-height: 300px; } + +#error-dialog { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: white; + padding: 15px; + opacity: 0.9; + text-wrap: wrap; + overflow: scroll; +} + +.text-red { + color: red; +} + +.-mb-20 { + margin-bottom: -20px; +} + +.mb-0 { + margin-bottom: 0; +} + +.mb-10 { + margin-bottom: 10px; +} + +pre { + text-wrap: wrap; +} + +pre.nowrap { + text-wrap: nowrap; +} + +.hidden { + display: none; +} +``` + +```js src/reportError.js hidden +function reportError({ title, error, componentStack, dismissable }) { + const errorDialog = document.getElementById("error-dialog"); + const errorTitle = document.getElementById("error-title"); + const errorMessage = document.getElementById("error-message"); + const errorBody = document.getElementById("error-body"); + const errorComponentStack = document.getElementById("error-component-stack"); + const errorStack = document.getElementById("error-stack"); + const errorClose = document.getElementById("error-close"); + const errorCause = document.getElementById("error-cause"); + const errorCauseMessage = document.getElementById("error-cause-message"); + const errorCauseStack = document.getElementById("error-cause-stack"); + const errorNotDismissible = document.getElementById("error-not-dismissible"); + + // Set the title + errorTitle.innerText = title; + + // Display error message and body + const [heading, body] = error.message.split(/\n(.*)/s); + errorMessage.innerText = heading; + if (body) { + errorBody.innerText = body; + } else { + errorBody.innerText = ''; + } + + // Display component stack + errorComponentStack.innerText = componentStack; + + // Display the call stack + // Since we already displayed the message, strip it, and the first Error: line. + errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; + + // Display the cause, if available + if (error.cause) { + errorCauseMessage.innerText = error.cause.message; + errorCauseStack.innerText = error.cause.stack; + errorCause.classList.remove('hidden'); + } else { + errorCause.classList.add('hidden'); + } + // Display the close button, if dismissible + if (dismissable) { + errorNotDismissible.classList.add('hidden'); + errorClose.classList.remove("hidden"); + } else { + errorNotDismissible.classList.remove('hidden'); + errorClose.classList.add("hidden"); + } + + // Show the dialog + errorDialog.classList.remove("hidden"); +} + +export function reportCaughtError({error, cause, componentStack}) { + reportError({ title: "Caught Error", error, componentStack, dismissable: true}); +} + +export function reportUncaughtError({error, cause, componentStack}) { + reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); +} + +export function reportRecoverableError({error, cause, componentStack}) { + reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +} +``` + +```js src/index.js active +import { hydrateRoot } from "react-dom/client"; +import App from "./App.js"; +import {reportCaughtError} from "./reportError"; +import "./styles.css"; + +const container = document.getElementById("root"); +const root = hydrateRoot(container, , { + onCaughtError: (error, errorInfo) => { + if (error.message !== 'Known error') { + reportCaughtError({ + error, + componentStack: errorInfo.componentStack + }); + } + } +}); +``` + +```js src/App.js +import { useState } from 'react'; +import { ErrorBoundary } from "react-error-boundary"; + +export default function App() { + const [error, setError] = useState(null); + + function handleUnknown() { + setError("unknown"); + } + + function handleKnown() { + setError("known"); + } + + return ( + <> + { + setError(null); + }} + > + {error != null && } + This error will not show the error dialog: + + This error will show the error dialog: + + + + + ); +} + +function fallbackRender({ resetErrorBoundary }) { + return ( +
    +

    Error Boundary

    +

    Something went wrong.

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

    Error Boundary

    +

    Something went wrong.

    + +
    + ); +} + +function Throw({error}) { + if (error === "known") { + throw new Error('Known error') + } else { + foo.bar = 'baz'; + } +} +``` + +```json package.json hidden +{ + "dependencies": { + "react": "19.0.0-rc-3edc000d-20240926", + "react-dom": "19.0.0-rc-3edc000d-20240926", + "react-scripts": "^5.0.0", + "react-error-boundary": "4.0.3" + }, + "main": "/index.js" +} +``` + +
    + +## Troubleshooting {/*troubleshooting*/} + + +### I'm getting an error: "You passed a second argument to root.render" {/*im-getting-an-error-you-passed-a-second-argument-to-root-render*/} + +A common mistake is to pass the options for `hydrateRoot` to `root.render(...)`: + + + +Warning: You passed a second argument to root.render(...) but it only accepts one argument. + + + +To fix, pass the root options to `hydrateRoot(...)`, not `root.render(...)`: +```js {2,5} +// 🚩 Wrong: root.render only takes one argument. +root.render(App, {onUncaughtError}); + +// ✅ Correct: pass options to createRoot. +const root = hydrateRoot(container, , {onUncaughtError}); +``` diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md index 610742735..9d1533213 100644 --- a/src/content/reference/react-dom/components/common.md +++ b/src/content/reference/react-dom/components/common.md @@ -246,22 +246,41 @@ These events fire for resources like [`