diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 40f7425630..0000000000 --- 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/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 0282504724..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,20 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: circleci/node:12 - steps: - - checkout - - restore_cache: - keys: - - dependencies-{{ checksum "yarn.lock" }} - - run: - name: Install - command: yarn install --pure-lockfile - - save_cache: - paths: - - node_modules - key: dependencies-{{ checksum "yarn.lock" }} - - run: - name: Check Prettier, ESLint, Flow - command: yarn ci-check diff --git a/.env.development b/.env.development new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.env.production b/.env.production new file mode 100644 index 0000000000..e403f96b68 --- /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 9425417154..4738cb6975 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,10 +1,3 @@ -node_modules/* - -# 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 a51454ef28..f8b03f98a1 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 836f6ec1eb..0000000000 --- a/.flowconfig +++ /dev/null @@ -1,35 +0,0 @@ -[ignore] - -/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/0-bug.yml b/.github/ISSUE_TEMPLATE/0-bug.yml new file mode 100644 index 0000000000..56d2e8540f --- /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 0000000000..c86557a116 --- /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 0000000000..ac0b480fe9 --- /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 0000000000..a47295e1e8 --- /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 0000000000..63e310e0ba --- /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/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..97f2a39ea0 --- /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/workflows/analyze.yml b/.github/workflows/analyze.yml new file mode 100644 index 0000000000..83e7f2e8a9 --- /dev/null +++ b/.github/workflows/analyze.yml @@ -0,0 +1,101 @@ +name: Analyze Bundle + +on: + pull_request: + push: + branches: + - main # change this if your default branch is named differently + workflow_dispatch: + +permissions: {} + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up node + 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: Restore next build + uses: actions/cache@v4 + id: restore-build-cache + env: + cache-name: cache-next-build + with: + 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 + + # 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@0.5.0 report + + - name: Upload bundle + uses: actions/upload-artifact@v4 + with: + path: .next/analyze/__bundle_analysis.json + name: bundle_analysis.json + + - name: Download base branch bundle stats + 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: .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. + # There are two configurable arguments that come from package.json: + # + # - budget: optional, set a budget (bytes) against which size changes are measured + # it's set to 350kb here by default, as informed by the following piece: + # https://infrequently.org/2021/03/the-performance-inequality-gap/ + # + # - red-status-percentage: sets the percent size increase where you get a red + # status indicator, defaults to 20% + # + # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis` + # entry in your package.json file. + - name: Compare with base branch bundle + if: success() && github.event.number + run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare + + - name: Upload analysis comment + uses: actions/upload-artifact@v4 + with: + name: 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@v4 + with: + name: pr_number + path: ./pr_number + + # The actual commenting happens in the other action, matching the guidance in + # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ diff --git a/.github/workflows/analyze_comment.yml b/.github/workflows/analyze_comment.yml new file mode 100644 index 0000000000..1e086b9b70 --- /dev/null +++ b/.github/workflows/analyze_comment.yml @@ -0,0 +1,57 @@ +name: Analyze Bundle (Comment) + +on: + workflow_run: + workflows: ['Analyze Bundle'] + types: + - completed + +permissions: {} + +jobs: + comment: + runs-on: ubuntu-latest + if: > + ${{ github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' }} + steps: + - name: Download base branch bundle stats + uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e + with: + workflow: analyze.yml + run_id: ${{ github.event.workflow_run.id }} + name: analysis_comment.txt + path: analysis_comment.txt + + - name: Download PR number + uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e + with: + workflow: analyze.yml + run_id: ${{ github.event.workflow_run.id }} + name: pr_number + path: pr_number + + - name: Get comment body + 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) + echo "pr-number=$pr_number" >> $GITHUB_OUTPUT + + - name: Comment + uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 + with: + header: next-bundle-analysis + number: ${{ steps.get-comment-body.outputs.pr-number }} + message: ${{ steps.get-comment-body.outputs.body }} diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml new file mode 100644 index 0000000000..2f5b2a497e --- /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_core_team_prs.yml b/.github/workflows/label_core_team_prs.yml new file mode 100644 index 0000000000..f9b3328ee5 --- /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/site_lint.yml b/.github/workflows/site_lint.yml new file mode 100644 index 0000000000..81a04601c2 --- /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 d1bde99cef..7bf71dbc5d 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/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000..dc0378c348 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +yarn lint-staged \ No newline at end of file diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 66df3b7ab2..0000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -12.16.1 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..96f1f96d2b --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +src/content/**/*.md diff --git a/.prettierrc b/.prettierrc index eb91e6abb7..19b54ad059 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/CONTRIBUTING.md b/CONTRIBUTING.md index e10f4f53e4..4c7e5ec74c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,19 +18,9 @@ This is a [good summary](https://medium.com/@kvosswinkel/coding-like-a-journalis 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. -**[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 ` - -## CoffeeScript integration {#coffeescript-integration} - -[Vjeux](http://blog.vjeux.com/) used the fact that JSX is just a syntactic sugar on-top of regular JS to rewrite the React front-page examples in CoffeeScript. - -> Multiple people asked what's the story about JSX and CoffeeScript. There is no JSX pre-processor for CoffeeScript and I'm not aware of anyone working on it. Fortunately, CoffeeScript is pretty expressive and we can play around the syntax to come up with something that is usable. -> -> ```javascript -> {div, h3, textarea} = React.DOM -> (div {className: 'MarkdownEditor'}, [ -> (h3 {}, 'Input'), -> (textarea {onKeyUp: @handleKeyUp, ref: 'textarea'}, -> @state.value -> ) -> ]) -> ``` -> -> [Read the full post...](http://blog.vjeux.com/2013/javascript/react-coffeescript.html) - -## Tutorial in Plain JavaScript {#tutorial-in-plain-javascript} - -We've seen a lot of people comparing React with various frameworks. [Ricardo Tomasi](http://ricardo.cc/) decided to re-implement the tutorial without any framework, just plain JavaScript. - -> Facebook & Instagram launched the React framework and an accompanying tutorial. Developer Vlad Yazhbin decided to rewrite that using AngularJS. The end result is pretty neat, but if you're like me you will not actually appreciate the HTML speaking for itself and doing all the hard work. So let's see what that looks like in plain javascript. -> -> [Read the full post...](http://ricardo.cc/2013/06/07/react-tutorial-rewritten-in-plain-javascript.html) diff --git a/content/blog/2013-07-02-react-v0-4-autobind-by-default.md b/content/blog/2013-07-02-react-v0-4-autobind-by-default.md deleted file mode 100644 index 9c98fd9b2a..0000000000 --- a/content/blog/2013-07-02-react-v0-4-autobind-by-default.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: "New in React v0.4: Autobind by Default" -author: [zpao] ---- - -React v0.4 is very close to completion. As we finish it off, we'd like to share with you some of the major changes we've made since v0.3. This is the first of several posts we'll be making over the next week. - - -## What is React.autoBind? {#what-is-reactautobind} - -If you take a look at most of our current examples, you'll see us using `React.autoBind` for event handlers. This is used in place of `Function.prototype.bind`. Remember that in JS, [function calls are late-bound](https://bonsaiden.github.io/JavaScript-Garden/#function.this). That means that if you simply pass a function around, the `this` used inside won't necessarily be the `this` you expect. `Function.prototype.bind` creates a new, properly bound, function so that when called, `this` is exactly what you expect it to be. - -Before we launched React, we would write this: - -```js{4} -React.createClass({ - onClick: function(event) {/* do something with this */}, - render: function() { - return + + + +

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? +

+
+ ` is not allowed. [Use `defaultValue` for initial content.](#providing-an-initial-value-for-a-text-area) +- If a text area receives a string `value` prop, it will be [treated as controlled.](#controlling-a-text-area-with-a-state-variable) +- A text area can't be both controlled and uncontrolled at the same time. +- A text area cannot switch between being controlled or uncontrolled over its lifetime. +- Every controlled text area needs an `onChange` event handler that synchronously updates its backing value. + +--- + +## Usage {/*usage*/} + +### Displaying a text area {/*displaying-a-text-area*/} + +Render `` is not supported. + + + +--- + +### Reading the text area value when submitting a form {/*reading-the-text-area-value-when-submitting-a-form*/} + +Add a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) around your textarea with a [`