diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 40f742563..000000000 --- a/.babelrc +++ /dev/null @@ -1,41 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "loose": true, - "modules": false, - "useBuiltIns": "usage", - "shippedProposals": true, - "targets": { - "browsers": [">0.25%", "not dead"], - } - } - ], - [ - "@babel/preset-react", - { - "useBuiltIns": true, - "pragma": "React.createElement", - } - ], - "@babel/flow" - ], - "plugins": [ - [ - "@babel/plugin-proposal-class-properties", - { - "loose": true - } - ], - "@babel/plugin-syntax-dynamic-import", - "babel-plugin-macros", - [ - "@babel/plugin-transform-runtime", - { - "helpers": true, - "regenerator": true - } - ] - ] -} \ No newline at end of file diff --git a/.env.development b/.env.development new file mode 100644 index 000000000..e69de29bb diff --git a/.env.production b/.env.production new file mode 100644 index 000000000..e403f96b6 --- /dev/null +++ b/.env.production @@ -0,0 +1 @@ +NEXT_PUBLIC_GA_TRACKING_ID = 'G-B1E83PJ3RT' \ No newline at end of file diff --git a/.eslintignore b/.eslintignore index ee6604687..4738cb697 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,13 +1,3 @@ -node_modules/* - -# Skip beta -beta/* - -# Ignore markdown files and examples -content/* - -# Ignore built files -public/* - -# Ignore examples -examples/* \ No newline at end of file +scripts +plugins +next.config.js diff --git a/.eslintrc b/.eslintrc index a51454ef2..f8b03f98a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,18 +1,19 @@ { - "extends": [ - "fbjs" - ], - "plugins": [ - "prettier", - "react" - ], - "parser": "babel-eslint", + "root": true, + "extends": "next/core-web-vitals", + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "eslint-plugin-react-compiler"], "rules": { - "relay/graphql-naming": 0, - "max-len": 0 + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", {"varsIgnorePattern": "^_"}], + "react-hooks/exhaustive-deps": "error", + "react/no-unknown-property": ["error", {"ignore": ["meta"]}], + "react-compiler/react-compiler": "error" }, "env": { "node": true, - "browser": true + "commonjs": true, + "browser": true, + "es6": true } } diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index baf4b0255..000000000 --- a/.flowconfig +++ /dev/null @@ -1,36 +0,0 @@ -[ignore] - -/beta/.* -/content/.* -/node_modules/.* -/public/.* - -[include] - -[libs] -./node_modules/fbjs/flow/lib/dev.js -./flow - -[options] -module.system=haste -module.system.node.resolve_dirname=node_modules -module.system.node.resolve_dirname=src - -esproposal.class_static_fields=enable -esproposal.class_instance_fields=enable -unsafe.enable_getters_and_setters=true - -munge_underscores=false - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FixMe -suppress_type=$FlowExpectedError - -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*www[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*www[a-z,_]*\\)?)\\)?:? #[0-9]+ -suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy -suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError - -[version] -^0.56.0 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 6987b42f9..941927bc9 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,8 +1,9 @@ diff --git a/.github/ISSUE_TEMPLATE/0-bug.yml b/.github/ISSUE_TEMPLATE/0-bug.yml new file mode 100644 index 000000000..56d2e8540 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/0-bug.yml @@ -0,0 +1,34 @@ +name: "🐛 Report a bug" +description: "Report a problem on the website." +title: "[Bug]: " +labels: ["bug: unconfirmed"] +body: + - type: textarea + attributes: + label: Summary + description: | + A clear and concise summary of what the bug is. + placeholder: | + Example bug report: + When I click the "Submit" button on "Feedback", nothing happens. + validations: + required: true + - type: input + attributes: + label: Page + description: | + What page(s) did you encounter this bug on? + placeholder: | + https://react.dev/ + validations: + required: true + - type: textarea + attributes: + label: Details + description: | + Please provide any additional details about the bug. + placeholder: | + Example details: + The "Submit" button is unresponsive. I've tried refreshing the page and using a different browser, but the issue persists. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/1-typo.yml b/.github/ISSUE_TEMPLATE/1-typo.yml new file mode 100644 index 000000000..c86557a11 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-typo.yml @@ -0,0 +1,34 @@ +name: "🤦 Typo or mistake" +description: "Report a typo or mistake in the docs." +title: "[Typo]: " +labels: ["type: typos"] +body: + - type: textarea + attributes: + label: Summary + description: | + A clear and concise summary of what the mistake is. + placeholder: | + Example: + The code example on the "useReducer" page includes an unused variable `nextId`. + validations: + required: true + - type: input + attributes: + label: Page + description: | + What page is the typo on? + placeholder: | + https://react.dev/ + validations: + required: true + - type: textarea + attributes: + label: Details + description: | + Please provide a explanation for why this is a mistake. + placeholder: | + Example mistake: + In the "useReducer" section of the "API Reference" page, the code example under "Writing a reducer function" includes an unused variable `nextId` that should be removed. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/2-suggestion.yml b/.github/ISSUE_TEMPLATE/2-suggestion.yml new file mode 100644 index 000000000..ac0b480fe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-suggestion.yml @@ -0,0 +1,34 @@ +name: "💡 Suggestions" +description: "Suggest a new page, section, or edit for an existing page." +title: "[Suggestion]: " +labels: ["type: documentation"] +body: + - type: textarea + attributes: + label: Summary + description: | + A clear and concise summary of what we should add. + placeholder: | + Example: + Add a new page for how to use React with TypeScript. + validations: + required: true + - type: input + attributes: + label: Page + description: | + What page is this about? + placeholder: | + https://react.dev/ + validations: + required: false + - type: textarea + attributes: + label: Details + description: | + Please provide a explanation for what you're suggesting. + placeholder: | + Example: + I think it would be helpful to have a page that explains how to use React with TypeScript. This could include a basic example of a component written in TypeScript, and a link to the TypeScript documentation. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/3-framework.yml b/.github/ISSUE_TEMPLATE/3-framework.yml new file mode 100644 index 000000000..a47295e1e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3-framework.yml @@ -0,0 +1,116 @@ +name: "📄 Suggest new framework" +description: "I am a framework author applying to be included as a recommended framework." +title: "[Framework]: " +labels: ["type: framework"] +body: + - type: markdown + attributes: + value: | + ## Apply to be included as a recommended React framework + + _This form is for framework authors to apply to be included as a recommended [React framework](https://react.dev/learn/start-a-new-react-project). If you are not a framework author, please contact the authors before submitting._ + + Our goal when recommending a framework is to start developers with a React project that solves common problems like code splitting, data fetching, routing, and HTML generation without any extra work later. We believe this will allow users to get started quickly with React, and scale their app to production. + + While we understand that many frameworks may want to be featured, this page is not a place to advertise every possible React framework or all frameworks that you can add React to. There are many great frameworks that offer support for React that are not listed in our guides. The frameworks we recommend have invested significantly in the React ecosystem, and collaborated with the React team to be compatible with our [full-stack React architecture vision](https://react.dev/learn/start-a-new-react-project#which-features-make-up-the-react-teams-full-stack-architecture-vision). + + To be included, frameworks must meet the following criteria: + + - **Free & open-source**: must be open source and free to use. + - **Well maintained**. must be actively maintained, providing bug fixes and improvements. + - **Active community**: must have a sufficiently large and active community to support users. + - **Clear onboarding**: must have clear install steps to install the React version of the framework. + - **Ecosystem compatibility**: must support using the full range of libraries and tools in the React ecosystem. + - **Self-hosting option**: must support an option to self-host applications without losing access to features. + - **Developer experience**. must allow developers to be productive by supporting features like Fast Refresh. + - **User experience**. must provide built-in support for common problems like routing and data-fetching. + - **Compatible with our future vision for React**. React evolves over time, and frameworks that do not align with React’s direction risk isolating their users from the main React ecosystem over time. To be included on this page we must feel confident that the framework is setting its users up for success with React over time. + + Please note, we have reviewed most of the popular frameworks available today, so it is unlikely we have not considered your framework already. But if you think we missed something, please complete the application below. + - type: input + attributes: + label: Name + description: | + What is the name of your framework? + validations: + required: true + - type: input + attributes: + label: Homepage + description: | + What is the URL of your homepage? + validations: + required: true + - type: input + attributes: + label: Install instructions + description: | + What is the URL of your getting started guide? + validations: + required: true + - type: dropdown + attributes: + label: Is your framework open source? + description: | + We only recommend free and open source frameworks. + options: + - 'No' + - 'Yes' + validations: + required: true + - type: textarea + attributes: + label: Well maintained + description: | + Please describe how your framework is actively maintained. Include recent releases, bug fixes, and improvements as examples. + validations: + required: true + - type: textarea + attributes: + label: Active community + description: | + Please describe your community. Include the size of your community, and links to community resources. + validations: + required: true + - type: textarea + attributes: + label: Clear onboarding + description: | + Please describe how a user can install your framework with React. Include links to any relevant documentation. + validations: + required: true + - type: textarea + attributes: + label: Ecosystem compatibility + description: | + Please describe any limitations your framework has with the React ecosystem. Include any libraries or tools that are not compatible with your framework. + validations: + required: true + - type: textarea + attributes: + label: Self-hosting option + description: | + Please describe how your framework supports self-hosting. Include any limitations to features when self-hosting. Also include whether you require a server to deploy your framework. + validations: + required: true + - type: textarea + attributes: + label: Developer Experience + description: | + Please describe how your framework provides a great developer experience. Include any limitations to React features like React DevTools, Chrome DevTools, and Fast Refresh. + validations: + required: true + - type: textarea + attributes: + label: User Experience + description: | + Please describe how your framework helps developers create high quality user experiences by solving common use-cases. Include specifics for how your framework offers built-in support for code-splitting, routing, HTML generation, and data-fetching in a way that avoids client/server waterfalls by default. Include details on how you offer features such as SSG and SSR. + validations: + required: true + - type: textarea + attributes: + label: Compatible with our future vision for React + description: | + Please describe how your framework aligns with our future vision for React. Include how your framework will evolve with React over time, and your plans to support future React features like React Server Components. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..63e310e0b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,7 @@ +contact_links: + - name: 📃 Bugs in React + url: https://github.com/facebook/react/issues/new/choose + about: This issue tracker is not for bugs in React. Please file React issues here. + - name: 🤔 Questions and Help + url: https://reactjs.org/community/support.html + about: This issue tracker is not for support questions. Please refer to the React community's help and discussion forums. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e34dda4af..16ebcbc62 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,11 @@ diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..97f2a39ea --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + # Disable Dependabot. Doing it here so it propagates to translation forks. + open-pull-requests-limit: 0 diff --git a/.github/labeler.yml b/.github/labeler.yml deleted file mode 100644 index 7768da2ba..000000000 --- a/.github/labeler.yml +++ /dev/null @@ -1,2 +0,0 @@ -beta: -- beta/**/* diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index ea9f6b573..83e7f2e8a 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -7,57 +7,63 @@ on: - main # change this if your default branch is named differently workflow_dispatch: +permissions: {} + 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: "14.x" + 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: - working-directory: 'beta' + 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 with: - path: beta/.next/cache + path: .next/cache # change this if you prefer a more strict cache key: ${{ runner.os }}-build-${{ env.cache-name }} - name: Build next.js app # change this if your site requires a custom build command run: ./node_modules/.bin/next build - working-directory: beta # Here's the first place where next-bundle-analysis' own script is used # This step pulls the raw bundle stats for the current bundle - name: Analyze bundle - run: npx -p nextjs-bundle-analysis report - working-directory: beta + 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: beta/.next/analyze/__bundle_analysis.json + path: .next/analyze/__bundle_analysis.json name: bundle_analysis.json - name: Download base branch bundle stats - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e if: success() && github.event.number with: workflow: analyze.yml branch: ${{ github.event.pull_request.base.ref }} name: bundle_analysis.json - path: beta/.next/analyze/base/bundle + path: .next/analyze/base/bundle # And here's the second place - this runs after we have both the current and # base branch bundle stats, and will compare them to determine what changed. @@ -75,19 +81,18 @@ jobs: - name: Compare with base branch bundle if: success() && github.event.number run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare - working-directory: beta - name: Upload analysis comment - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: analysis_comment.txt - path: beta/.next/analyze/__bundle_analysis_comment.txt + path: .next/analyze/__bundle_analysis_comment.txt - name: Save PR number 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/analyze_comment.yml b/.github/workflows/analyze_comment.yml index 8166089fd..1e086b9b7 100644 --- a/.github/workflows/analyze_comment.yml +++ b/.github/workflows/analyze_comment.yml @@ -2,10 +2,12 @@ name: Analyze Bundle (Comment) on: workflow_run: - workflows: ["Analyze Bundle"] + workflows: ['Analyze Bundle'] types: - completed +permissions: {} + jobs: comment: runs-on: ubuntu-latest @@ -14,7 +16,7 @@ jobs: github.event.workflow_run.conclusion == 'success' }} steps: - name: Download base branch bundle stats - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e with: workflow: analyze.yml run_id: ${{ github.event.workflow_run.id }} @@ -22,7 +24,7 @@ jobs: path: analysis_comment.txt - name: Download PR number - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e with: workflow: analyze.yml run_id: ${{ github.event.workflow_run.id }} @@ -33,40 +35,23 @@ jobs: id: get-comment-body if: success() run: | + echo 'body<> $GITHUB_OUTPUT + echo '' >> $GITHUB_OUTPUT + echo '## Size changes' >> $GITHUB_OUTPUT + echo '' >> $GITHUB_OUTPUT + echo '
' >> $GITHUB_OUTPUT + echo '' >> $GITHUB_OUTPUT + cat analysis_comment.txt/__bundle_analysis_comment.txt >> $GITHUB_OUTPUT + echo '' >> $GITHUB_OUTPUT + echo '
' >> $GITHUB_OUTPUT + echo '' >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT pr_number=$(cat pr_number/pr_number) - body=$(cat analysis_comment.txt/__bundle_analysis_comment.txt) - body="## Size Changes -
- - ${body} - -
" - body="${body//'%'/'%25'}" - body="${body//$'\n'/'%0A'}" - body="${body//$'\r'/'%0D'}" - echo ::set-output name=body::$body - echo ::set-output name=pr-number::$pr_number - - - name: Find Comment - uses: peter-evans/find-comment@v1 - if: success() - id: fc - with: - issue-number: ${{ steps.get-comment-body.outputs.pr-number }} - body-includes: "" - - - name: Create Comment - uses: peter-evans/create-or-update-comment@v1.4.4 - if: success() && steps.fc.outputs.comment-id == 0 - with: - issue-number: ${{ steps.get-comment-body.outputs.pr-number }} - body: ${{ steps.get-comment-body.outputs.body }} + echo "pr-number=$pr_number" >> $GITHUB_OUTPUT - - name: Update Comment - uses: peter-evans/create-or-update-comment@v1.4.4 - if: success() && steps.fc.outputs.comment-id != 0 + - name: Comment + uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 with: - issue-number: ${{ steps.get-comment-body.outputs.pr-number }} - body: ${{ steps.get-comment-body.outputs.body }} - comment-id: ${{ steps.fc.outputs.comment-id }} - edit-mode: replace \ No newline at end of file + header: next-bundle-analysis + number: ${{ steps.get-comment-body.outputs.pr-number }} + message: ${{ steps.get-comment-body.outputs.body }} diff --git a/.github/workflows/beta_site_lint.yml b/.github/workflows/beta_site_lint.yml deleted file mode 100644 index a9cacd7f0..000000000 --- a/.github/workflows/beta_site_lint.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Beta Site Lint / Heading ID check - -on: - push: - branches: - - main # change this if your default branch is named differently - pull_request: - types: [opened, synchronize, reopened] - -jobs: - lint: - runs-on: ubuntu-latest - - name: Lint on node 12.x and ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Use Node.js 12.x - uses: actions/setup-node@v1 - with: - node-version: 12.x - - - name: Install deps and build (with cache) - uses: bahmutov/npm-install@v1.7.10 - with: - working-directory: 'beta' - - - - name: Lint codebase - run: cd beta && yarn ci-check diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml new file mode 100644 index 000000000..2f5b2a497 --- /dev/null +++ b/.github/workflows/discord_notify.yml @@ -0,0 +1,32 @@ +name: Discord Notify + +on: + pull_request_target: + types: [opened, ready_for_review] + +permissions: {} + +jobs: + check_maintainer: + uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main + permissions: + # Used by check_maintainer + contents: read + with: + actor: ${{ github.event.pull_request.user.login }} + + notify: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + needs: check_maintainer + 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 }} diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml deleted file mode 100644 index 90a961d4c..000000000 --- a/.github/workflows/label.yml +++ /dev/null @@ -1,22 +0,0 @@ -# This workflow will triage pull requests and apply a label based on the -# paths that are modified in the pull request. -# -# To use this workflow, you will need to set up a .github/labeler.yml -# file with configuration. For more information, see: -# https://github.com/actions/labeler - -name: Labeler -on: [pull_request_target] - -jobs: - label: - - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - - steps: - - uses: actions/labeler@v2 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/label_core_team_prs.yml b/.github/workflows/label_core_team_prs.yml new file mode 100644 index 000000000..f9b3328ee --- /dev/null +++ b/.github/workflows/label_core_team_prs.yml @@ -0,0 +1,41 @@ +name: Label Core Team PRs + +on: + pull_request_target: + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + check_maintainer: + uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main + permissions: + # Used by check_maintainer + contents: read + with: + actor: ${{ github.event.pull_request.user.login }} + + label: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + runs-on: ubuntu-latest + needs: check_maintainer + permissions: + # Used to add labels on issues + issues: write + # Used to add labels on PRs + pull-requests: write + steps: + - name: Label PR as React Core Team + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ github.event.number }}, + labels: ['React Core Team'] + }); diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml deleted file mode 100644 index eed7b3d94..000000000 --- a/.github/workflows/nodejs.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Lint / Flow check - -on: - push: - branches: - - main # change this if your default branch is named differently - pull_request: - types: [opened, synchronize, reopened] - -jobs: - lint: - runs-on: ubuntu-latest - - name: Lint on node 12.x and ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Use Node.js 12.x - uses: actions/setup-node@v1 - with: - node-version: 12.x - - - name: Install deps and build (with cache) - uses: bahmutov/npm-install@v1.7.10 - - - name: Lint codebase - run: yarn ci-check diff --git a/.github/workflows/site_lint.yml b/.github/workflows/site_lint.yml new file mode 100644 index 000000000..81a04601c --- /dev/null +++ b/.github/workflows/site_lint.yml @@ -0,0 +1,37 @@ +name: Site Lint / Heading ID check + +on: + push: + branches: + - main # change this if your default branch is named differently + pull_request: + types: [opened, synchronize, reopened] + +permissions: {} + +jobs: + lint: + runs-on: ubuntu-latest + + name: Lint on node 20.x and ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: yarn + cache-dependency-path: yarn.lock + + - 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 e81f1af62..7bf71dbc5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,41 @@ -.cache -.DS_STORE -.idea -node_modules -/public -yarn-error.log \ No newline at end of file +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem +tsconfig.tsbuildinfo + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +# external fonts +public/fonts/**/Optimistic_*.woff2 + +# rss +public/rss.xml diff --git a/beta/.husky/pre-commit b/.husky/pre-commit similarity index 87% rename from beta/.husky/pre-commit rename to .husky/pre-commit index bbf64071e..dc0378c34 100755 --- a/beta/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -cd beta yarn lint-staged \ No newline at end of file diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 898e643b0..000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -12.22.0 diff --git a/beta/.prettierignore b/.prettierignore similarity index 100% rename from beta/.prettierignore rename to .prettierignore diff --git a/.prettierrc b/.prettierrc index eb91e6abb..19b54ad05 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,8 +1,21 @@ { "bracketSpacing": false, - "jsxBracketSameLine": true, - "parser": "flow", - "printWidth": 80, "singleQuote": true, - "trailingComma": "all" -} \ No newline at end of file + "bracketSameLine": true, + "trailingComma": "es5", + "printWidth": 80, + "overrides": [ + { + "files": "*.css", + "options": { + "parser": "css" + } + }, + { + "files": "*.md", + "options": { + "parser": "mdx" + } + } + ] +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index f049d4c53..5f21c144d 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,76 +1,77 @@ -# Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to make participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies within all project spaces, and it also applies when -an individual is representing the project or its community in public spaces. -Examples of representing a project or community include using an official -project e-mail address, posting via an official social media account, or acting -as an appointed representative at an online or offline event. Representation of -a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at . All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +# Código de conducta + +## Nuestro compromiso + +En aras de fomentar un entorno abierto y acogedor, nosotros como contribuidores y +mantenedores nos comprometemos a hacer que la participación en nuestro proyecto y +comunidad sea una experiencia libre de acoso para todos, independientemente de la +edad, discapacidad, etnia, características sexuales, identidad y expresión de género, +nivel de experiencia, educación, estatus socioeconómico, nacionalidad, apariencia +personal, raza, religión o identidad y orientación sexual. + +## Nuestros Estándares + +Ejemplos de comportamientos que contribuyen a crear un entorno positivo +incluyen: + +* Utilizar un lenguaje acogedor e inclusivo. +* Ser respetuoso con los distintos puntos de vista y experiencias. +* Aceptar con gracia las críticas constructivas. +* Centrarse en lo que es mejor para la comunidad. +* Mostrar empatía hacia otros miembros de la comunidad. + +Algunos ejemplos de comportamiento inaceptable de los participantes son: + +* El uso de lenguaje o imágenes sexualizados y la atención o insinuaciones sexuales + no deseadas. +* Trolling, comentarios insultantes/derogatorios y ataques personales o políticos. +* Acoso público o privado. +* Publicar información privada de otros, como una dirección física o + electrónica, sin permiso explícito. +* Otras conductas que puedan considerarse razonablemente inapropiadas en un entorno + profesional. + +## Nuestras responsabilidades + +Los mantenedores del proyecto son responsables de aclarar los estándares de +comportamiento aceptable y se espera de ellos que tomen medidas correctivas +apropiadas y justas en respuesta a cualquier instancia de comportamiento inaceptable. + +Los mantenedores del proyecto tienen el derecho y la responsabilidad de eliminar, editar +o rechazar comentarios, confirmaciones, código, ediciones wiki, problemas y otras +contribuciones que no se ajusten a este Código de Conducta, o de prohibir temporal o +permanentemente el acceso al proyecto a cualquier contribuidor por otros comportamientos +inaceptables, inapropiados, amenazantes, ofensivos o dañinos. + +## Ámbito + +Este Código de Conducta aplica a todos los espacios del proyecto, y también aplica a +individuos que representen al proyecto o a su comunidad en espacios públicos. +Ejemplos de representación del proyecto o la comunidad incluyen el uso de una dirección +de correo electrónico oficial del proyecto, la publicación a través de una cuenta +oficial en las redes sociales o actuar como representante designado en un evento +en línea o fuera de línea. La representación del proyecto puede ser definida y aclarada +por los mantenedores del proyecto. + +## Cumplimiento + +Los casos de comportamiento abusivo, acosador o inaceptable pueden ser reportados +poniéndose en contacto con el equipo del proyecto en . Todas +las quejas serán revisadas e investigadas y darán lugar a la respuesta se considere +necesaria y adecuada a las circunstancias. El equipo del proyecto esta obligado a +mantener la confidencialidad con respecto al denunciante de un incidente. +Podrán publicarse por separado más detalles sobre políticas de cumplimiento específicas. + +Los mantenedores del proyecto que no sigan o hagan cumplir el Código de Conducta de +buena fe pueden enfrentarse a repercusiones temporales o permanentes, según determinen +otros miembros de la dirección del proyecto. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +Este Código de Conducta es una adaptación del [Pacto de Colaboradores][homepage], versión 1.4, +disponible en https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org -For answers to common questions about this code of conduct, see +Para obtener respuestas a preguntas comunes sobre este código de conducta, consulta https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e10f4f53e..f0aef65dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,62 +1,52 @@ -# Contributing +# Contribuir -Thank you for your interest in contributing to the React Docs! +¡Gracias por tu interés en contribuir a React Docs! -## Code of Conduct +## Código de conducta -Facebook has adopted a Code of Conduct that we expect project -participants to adhere to. Please [read the full text](https://code.facebook.com/codeofconduct) -so that you can understand what actions will and will not be tolerated. +Facebook ha adoptado un Código de Conducta que esperamos que cumplan +del proyecto. Por favor, [lee el texto completo](https://code.facebook.com/codeofconduct) +para que puedas comprender qué acciones se tolerarán y cuáles no. -## Technical Writing Tips +## Consejos de redacción técnica -This is a [good summary](https://medium.com/@kvosswinkel/coding-like-a-journalist-ee52360a16bc) for things to keep in mind when writing technical docs. +Este es un [buen resumen](https://medium.com/@kvosswinkel/coding-like-a-journalist-ee52360a16bc) de cosas a tener en cuenta al escribir documentos técnicos. -## Guidelines for Text +## Pautas para el texto -**Different sections intentionally have different styles.** +**Las distintas secciones tienen intencionadamente estilos diferentes.** -The documentation is divided into sections to cater to different learning styles and use cases. When editing an article, try to match the surrounding text in tone and style. When creating a new article, try to match the tone of the other articles in the same section. Learn about the motivation behind each section below. +La documentación está dividida en secciones para atender a diferentes estilos de aprendizaje y casos de uso. Cuando edites un artículo, intenta igualar el tono y el estilo del texto que lo rodea. Al crear un nuevo artículo, intenta que coincida con el tono de los demás artículos de la misma sección. Conoce a continuación la motivación de cada sección. -**[Installation](https://reactjs.org/docs/getting-started.html)** gives an overview of the docs, and demonstrates two different ways to use it: either as a simple ` - - - -`, - ]); - const url = window.URL.createObjectURL(blob); - const a = document.createElement('a'); - a.style.display = 'none'; - a.href = url; - a.download = 'sandbox.html'; - document.body.appendChild(a); - a.click(); - window.URL.revokeObjectURL(url); - }; - - return ( - - ); -} diff --git a/beta/src/components/MDX/Sandpack/Error.tsx b/beta/src/components/MDX/Sandpack/Error.tsx deleted file mode 100644 index 61344ebac..000000000 --- a/beta/src/components/MDX/Sandpack/Error.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -interface ErrorType { - title?: string; - message: string; - column?: number; - line?: number; - path?: string; -} - -export function Error({error}: {error: ErrorType}) { - const {message, title} = error; - - return ( -
-

{title || 'Error'}

-
-        {message}
-      
-
- ); -} diff --git a/beta/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx b/beta/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx deleted file mode 100644 index 42a2d2743..000000000 --- a/beta/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -import {UnstyledOpenInCodeSandboxButton} from '@codesandbox/sandpack-react'; -import {IconNewPage} from '../../Icon/IconNewPage'; - -export const OpenInCodeSandboxButton = () => { - return ( - - - Fork - - ); -}; diff --git a/beta/src/components/MDX/Sandpack/Preview.tsx b/beta/src/components/MDX/Sandpack/Preview.tsx deleted file mode 100644 index 20c8311ee..000000000 --- a/beta/src/components/MDX/Sandpack/Preview.tsx +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -/* eslint-disable react-hooks/exhaustive-deps */ -import {useRef, useState, useEffect, useMemo} from 'react'; -import { - useSandpack, - LoadingOverlay, - SandpackStack, -} from '@codesandbox/sandpack-react'; -import cn from 'classnames'; -import {Error} from './Error'; -import {SandpackConsole} from './Console'; -import type {LintDiagnostic} from './useSandpackLint'; - -/** - * TODO: can we use React.useId? - */ -const generateRandomId = (): string => - Math.floor(Math.random() * 10000).toString(); - -type CustomPreviewProps = { - className?: string; - customStyle?: Record; - isExpanded: boolean; - lintErrors: LintDiagnostic; -}; - -function useDebounced(value: any): any { - const ref = useRef(null); - const [saved, setSaved] = useState(value); - useEffect(() => { - clearTimeout(ref.current); - ref.current = setTimeout(() => { - setSaved(value); - }, 300); - }, [value]); - return saved; -} - -export function Preview({ - customStyle, - isExpanded, - className, - lintErrors, -}: CustomPreviewProps) { - const {sandpack, listen} = useSandpack(); - const [isReady, setIsReady] = useState(false); - const [iframeComputedHeight, setComputedAutoHeight] = useState( - null - ); - - let { - error: rawError, - registerBundler, - unregisterBundler, - errorScreenRegisteredRef, - openInCSBRegisteredRef, - loadingScreenRegisteredRef, - status, - } = sandpack; - - if ( - rawError && - rawError.message === '_csbRefreshUtils.prelude is not a function' - ) { - // Work around a noisy internal error. - rawError = null; - } - - // Memoized because it's fed to debouncing. - const firstLintError = useMemo(() => { - if (lintErrors.length === 0) { - return null; - } else { - const {line, column, message} = lintErrors[0]; - return { - title: 'Lint Error', - message: `${line}:${column} - ${message}`, - }; - } - }, [lintErrors]); - - if (rawError == null || rawError.title === 'Runtime Exception') { - if (firstLintError !== null) { - rawError = firstLintError; - } - } - - if (rawError != null && rawError.title === 'Runtime Exception') { - rawError.title = 'Runtime Error'; - } - - // It changes too fast, causing flicker. - const error = useDebounced(rawError); - - const clientId = useRef(generateRandomId()); - const iframeRef = useRef(null); - - // SandpackPreview immediately registers the custom screens/components so the bundler does not render any of them - // TODO: why are we doing this during render? - openInCSBRegisteredRef.current = true; - errorScreenRegisteredRef.current = true; - loadingScreenRegisteredRef.current = true; - - useEffect(function createBundler() { - const iframeElement = iframeRef.current!; - registerBundler(iframeElement, clientId.current); - - return () => { - unregisterBundler(clientId.current); - }; - }, []); - - useEffect( - function bundlerListener() { - const unsubscribe = listen((message: any) => { - if (message.type === 'resize') { - setComputedAutoHeight(message.height); - } else if (message.type === 'start') { - if (message.firstLoad) { - setIsReady(false); - } - } else if (message.type === 'done') { - setIsReady(true); - } - }, clientId.current); - - return () => { - setIsReady(false); - setComputedAutoHeight(null); - unsubscribe(); - }; - }, - [status === 'idle'] - ); - - const overrideStyle = error - ? { - // Don't collapse errors - maxHeight: undefined, - } - : null; - const hideContent = !isReady || error; - - // WARNING: - // The layout and styling here is convoluted and really easy to break. - // If you make changes to it, you need to test different cases: - // - Content -> (compile | runtime) error -> content editing flow should work. - // - Errors should expand parent height rather than scroll. - // - Long sandboxes should scroll unless "show more" is toggled. - // - Expanded sandboxes ("show more") have sticky previews and errors. - // - Sandboxes have autoheight based on content. - // - That autoheight should be measured correctly! (Check some long ones.) - // - You shouldn't see nested scrolls (that means autoheight is borked). - // - Ideally you shouldn't see a blank preview tile while recompiling. - // - Container shouldn't be horizontally scrollable (even while loading). - // - It should work on mobile. - // The best way to test it is to actually go through some challenges. - - return ( - -
-
- - -## Snake in React {/*snake-in-react*/} - -[Tom Occhino](http://tomocchino.com/) implemented Snake in 150 lines with React. - -> [Check the source on GitHub](https://github.com/tomocchino/react-snake/blob/master/src/snake.js) -> ->
diff --git a/beta/src/content/blog/2013/07/11/react-v0-4-prop-validation-and-default-values.md b/beta/src/content/blog/2013/07/11/react-v0-4-prop-validation-and-default-values.md deleted file mode 100644 index 59a41733c..000000000 --- a/beta/src/content/blog/2013/07/11/react-v0-4-prop-validation-and-default-values.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: 'New in React v0.4: Prop Validation and Default Values' -author: [zpao] ---- - -Many of the questions we got following the public launch of React revolved around `props`, specifically that people wanted to do validation and to make sure their components had sensible defaults. - -## Validation {/*validation*/} - -Oftentimes you want to validate your `props` before you use them. Perhaps you want to ensure they are a specific type. Or maybe you want to restrict your prop to specific values. Or maybe you want to make a specific prop required. This was always possible — you could have written validations in your `render` or `componentWillReceiveProps` functions, but that gets clunky fast. - -React v0.4 will provide a nice easy way for you to use built-in validators, or to even write your own. - -```js -React.createClass({ - propTypes: { - // An optional string prop named "description". - description: React.PropTypes.string, - - // A required enum prop named "category". - category: React.PropTypes.oneOf(['News','Photos']).isRequired, - - // A prop named "dialog" that requires an instance of Dialog. - dialog: React.PropTypes.instanceOf(Dialog).isRequired - }, - ... -}); -``` - -## Default Values {/*default-values*/} - -One common pattern we've seen with our React code is to do something like this: - -```js -React.createClass({ - render: function () { - var value = this.props.value || 'default value'; - return
{value}
; - }, -}); -``` - -Do this for a few `props` across a few components and now you have a lot of redundant code. Starting with React v0.4, you can provide default values in a declarative way: - -```js -React.createClass({ - getDefaultProps: function() { - return { - value: 'default value' - }; - } - ... -}); -``` - -We will use the cached result of this function before each `render`. We also perform all validations before each `render` to ensure that you have all of the data you need in the right form before you try to use it. - ---- - -Both of these features are entirely optional. We've found them to be increasingly valuable at Facebook as our applications grow and evolve, and we hope others find them useful as well. diff --git a/beta/src/content/blog/2013/07/17/react-v0-4-0.md b/beta/src/content/blog/2013/07/17/react-v0-4-0.md deleted file mode 100644 index 65a730234..000000000 --- a/beta/src/content/blog/2013/07/17/react-v0-4-0.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: 'React v0.4.0' -author: [zpao] ---- - -Over the past 2 months we've been taking feedback and working hard to make React even better. We fixed some bugs, made some under-the-hood improvements, and added several features that we think will improve the experience developing with React. Today we're proud to announce the availability of React v0.4! - -This release could not have happened without the support of our growing community. Since launch day, the community has contributed blog posts, questions to the [Google Group](https://groups.google.com/group/reactjs), and issues and pull requests on GitHub. We've had contributions ranging from documentation improvements to major changes to React's rendering. We've seen people integrate React into the tools they're using and the products they're building, and we're all very excited to see what our budding community builds next! - -React v0.4 has some big changes. We've also restructured the documentation to better communicate how to use React. We've summarized the changes below and linked to documentation where we think it will be especially useful. - -When you're ready, [go download it](/docs/installation.html)! - -### React {/*react*/} - -- Switch from using `id` attribute to `data-reactid` to track DOM nodes. This allows you to integrate with other JS and CSS libraries more easily. -- Support for more DOM elements and attributes (e.g., ``) -- Improved server-side rendering APIs. `React.renderComponentToString(, callback)` allows you to use React on the server and generate markup which can be sent down to the browser. -- `prop` improvements: validation and default values. [Read our blog post for details...](/blog/2013/07/11/react-v0-4-prop-validation-and-default-values.html) -- Support for the `key` prop, which allows for finer control over reconciliation. [Read the docs for details...](/docs/multiple-components.html) -- Removed `React.autoBind`. [Read our blog post for details...](/blog/2013/07/02/react-v0-4-autobind-by-default.html) -- Improvements to forms. We've written wrappers around ``, ` -
- - - - -

That's right!

- - -``` - - - -Manipulating the UI imperatively works well enough for isolated examples, but it gets exponentially more difficult to manage in more complex systems. Imagine updating a page full of different forms like this one. Adding a new UI element or a new interaction would require carefully checking all existing code to make sure you haven't introduced a bug (for example, forgetting to show or hide something). - -React was built to solve this problem. - -In React, you don't directly manipulate the UI--meaning you don't enable, disable, show, or hide components directly. Instead, you **declare what you want to show,** and React figures out how to update the UI. Think of getting into a taxi and telling the driver where you want to go instead of telling them exactly where to turn. It's the driver's job to get you there, and they might even know some shortcuts you haven't considered! - - - -## Thinking about UI declaratively {/*thinking-about-ui-declaratively*/} - -You've seen how to implement a form imperatively above. To better understand how to think in React, you'll walk through reimplementing this UI in React below: - -1. **Identify** your component's different visual states -2. **Determine** what triggers those state changes -3. **Represent** the state in memory using `useState` -4. **Remove** any non-essential state variables -5. **Connect** the event handlers to set the state - -### Step 1: Identify your component's different visual states {/*step-1-identify-your-components-different-visual-states*/} - -In computer science, you may hear about a ["state machine"](https://en.wikipedia.org/wiki/Finite-state_machine) being in one of several “states”. If you work with a designer, you may have seen mockups for different "visual states". React stands at the intersection of design and computer science, so both of these ideas are sources of inspiration. - -First, you need to visualize all the different "states" of the UI the user might see: - -* **Empty**: Form has a disabled "Submit" button. -* **Typing**: Form has an enabled "Submit" button. -* **Submitting**: Form is completely disabled. Spinner is shown. -* **Success**: "Thank you" message is shown instead of a form. -* **Error**: Same as Typing state, but with an extra error message. - -Just like a designer, you'll want to "mock up" or create "mocks" for the different states before you add logic. For example, here is a mock for just the visual part of the form. This mock is controlled by a prop called `status` with a default value of `'empty'`: - - - -```js -export default function Form({ - status = 'empty' -}) { - if (status === 'success') { - return

That's right!

- } - return ( - <> -

City quiz

-

- In which city is there a billboard that turns air into drinkable water? -

-
- -``` - -En React, un ` +
+ + + +
+

¡Correcto!

+ + +``` + +
+ +Manipular la UI de forma imperativa funciona lo suficientemente bien en ejemplos aislados, pero se vuelve mas complicado de manejar de forma exponencial en sistemas complejos. Imagina actualizar una pagina llena de formularios diferentes como este. Añadir un elemento nuevo a la UI o una nueva interacción requeriría revisar todo el código existente meticulosamente para asegurarse de no haber introducido un bug (por ejemplo, olvidando mostrar u ocultar algo). + +React fue construido para solucionar este problema. + +En React, no necesitas manipular directamente la UI,lo que significa que no necesitas habilitar, deshabilitar, mostrar, u ocultar los componentes directamente. En su lugar, tú **declaras lo que quieres mostrar,** y React averigua cómo actualizar la UI. Piensa en ello como montarte en un taxi y decirle al conductor a donde quieres ir en lugar de decirle paso por paso que hacer. Es el trabajo del conductor llevarte a tu destino, ¡e incluso conocerá algún atajo que no habías considerado! + + + +## Pensar en la UI de forma declarativa {/*thinking-about-ui-declaratively*/} + +Arriba has visto como implementar un formulario de forma imperativa. Para entender mejor como pensar en React, recorrerás el ejemplo reimplementando esta UI en React más abajo: + +1. **Identifica** los diferentes estados visuales de tu componente +2. **Determina** qué produce esos cambios de estado +3. **Representa** el estado en memoria usando `useState` +4. **Elimina** cualquier variable de estado no esencial +5. **Conecta** los controladores de eventos para actualizar el estado + +### Paso 1: Identifica los diferentes estados visuales de tu componente {/*step-1-identify-your-components-different-visual-states*/} + +En las ciencias de la computación, tal vez escucharás algo sobre una ["máquina de estado"](https://en.wikipedia.org/wiki/Finite-state_machine) siendo este uno de muchos "estados". Si trabajas con un diseñador, habrás visto bocetos para diferentes "estados visuales". React se encuentra en un punto intermedio de diseño y ciencias de la computación, asi que ambas ideas son fuentes de inspiración. + +Primero, necesitas visualizar todos los diferentes "estados" de la UI que el usuario pueda ver: + +* **Vacío**: El formulario tiene deshabilitado el botón "Enviar". +* **Escribiendo**: El formulario tiene habilitado el botón "Enviar". +* **Enviando**: El formulario está completamente deshabilitado. Se muestra un indicador de carga. +* **Éxito**: El mensaje "Gracias" se muestra en lugar del formulario. +* **Error**: Igual que el estado de Escribiendo, pero con un mensaje de error extra. + +Al igual que un diseñador, querrás "esbozar" o crear "bocetos" para los diferentes estados antes de añadir tu lógica. Por ejemplo, aquí hay un boceto solo para la parte visual del formulario. Este boceto es controlado por una prop llamado `status` con valor por defecto de `'empty'`: + + + +```js +export default function Form({ + status = 'empty' +}) { + if (status === 'success') { + return

¡Correcto!

+ } + return ( + <> +

Cuestionario sobre ciudades

+

+ ¿En qué ciudad hay un cartel que convierte el aire en agua potable? +

+
+ `. [Usa `defaultValue` para el contenido inicial.](#providing-an-initial-value-for-a-text-area) +- Si un text area recibe una prop `value` string, este será [tratado como controlado.](#controlling-a-text-area-with-a-state-variable) +- Un text area no puede ser controlado y no controlado a la vez. +- Un text area no puede alternar entre ser controlado o no controlado a lo largo de su vida. +- Todo text area controlado necesita un controlador de evento `onChange` que actualice su valor de manera síncrona. + +--- + +## Uso {/*usage*/} + +### Mostrar un text area {/*displaying-a-text-area*/} + +Renderiza ``. + + + +--- + +### Leer el valor de text area al enviar un formulario {/*reading-the-text-area-value-when-submitting-a-form*/} + + Agrega un [``](https://developer.mozilla.org/es/docs/Web/HTML/Element/form) alrededor de tu text area con un [`