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..a692f21c7 --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +SANDPACK_BARE_COMPONENTS=true \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 000000000..445c9c4d0 --- /dev/null +++ b/.env.production @@ -0,0 +1,2 @@ +NEXT_PUBLIC_GA_TRACKING_ID = 'UA-41298772-4' +SANDPACK_BARE_COMPONENTS=true \ 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..147e54607 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,18 +1,16 @@ { - "extends": [ - "fbjs" - ], - "plugins": [ - "prettier", - "react" - ], - "parser": "babel-eslint", + "root": true, + "extends": "next/core-web-vitals", + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], "rules": { - "relay/graphql-naming": 0, - "max-len": 0 + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "warn" }, "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/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e34dda4af..7e4f6d2f2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ Thank you for the PR! Contributors like you keep React awesome! Please see the Contribution Guide for guidelines: -https://github.com/reactjs/reactjs.org/blob/main/CONTRIBUTING.md +https://github.com/reactjs/react.dev/blob/main/CONTRIBUTING.md If your PR references an existing issue, please add the issue number below 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..c447a2cdb 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -20,8 +20,6 @@ jobs: - name: Install dependencies uses: bahmutov/npm-install@v1.7.10 - with: - working-directory: 'beta' - name: Restore next build uses: actions/cache@v2 @@ -29,25 +27,23 @@ jobs: 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 - name: Upload bundle uses: actions/upload-artifact@v2 with: - path: beta/.next/analyze/__bundle_analysis.json + path: .next/analyze/__bundle_analysis.json name: bundle_analysis.json - name: Download base branch bundle stats @@ -57,7 +53,7 @@ jobs: 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,13 +71,12 @@ 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 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 diff --git a/.github/workflows/analyze_comment.yml b/.github/workflows/analyze_comment.yml index 8166089fd..bd73b6b4e 100644 --- a/.github/workflows/analyze_comment.yml +++ b/.github/workflows/analyze_comment.yml @@ -33,19 +33,19 @@ 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 + echo "pr-number=$pr_number" >> $GITHUB_OUTPUT - name: Find Comment uses: peter-evans/find-comment@v1 @@ -69,4 +69,4 @@ jobs: 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 + edit-mode: replace 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/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/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..bf446393a --- /dev/null +++ b/.github/workflows/site_lint.yml @@ -0,0 +1,27 @@ +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] + +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/.gitignore b/.gitignore index e81f1af62..d8bec488b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,38 @@ -.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 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 66df3b7ab..000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -12.16.1 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..96f1f96d2 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +src/content/**/*.md 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/CONTRIBUTING.md b/CONTRIBUTING.md index e10f4f53e..0e861af35 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 ` - - - -`, - ]); - 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 257ce0369..000000000 --- a/beta/src/components/MDX/Sandpack/Error.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -import * as React from 'react'; - -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/FilesDropdown.tsx b/beta/src/components/MDX/Sandpack/FilesDropdown.tsx deleted file mode 100644 index 68d068ad7..000000000 --- a/beta/src/components/MDX/Sandpack/FilesDropdown.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -import * as React from 'react'; -import cn from 'classnames'; -import {IconChevron} from '../../Icon/IconChevron'; -import {useSandpack} from '@codesandbox/sandpack-react'; -import {Listbox} from '@headlessui/react'; - -const getFileName = (filePath: string): string => { - const lastIndexOfSlash = filePath.lastIndexOf('/'); - return filePath.slice(lastIndexOfSlash + 1); -}; - -export function FilesDropdown() { - const {sandpack} = useSandpack(); - const {openPaths, setActiveFile, activePath} = sandpack; - return ( - - - {({open}) => ( - - {getFileName(activePath)} - - - - - )} - - - {openPaths.map((filePath: string) => ( - - {getFileName(filePath)} - - ))} - - - ); -} diff --git a/beta/src/components/MDX/Sandpack/NavigationBar.tsx b/beta/src/components/MDX/Sandpack/NavigationBar.tsx deleted file mode 100644 index 6114ef673..000000000 --- a/beta/src/components/MDX/Sandpack/NavigationBar.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -import * as React from 'react'; -import { - FileTabs, - useSandpack, - useSandpackNavigation, -} from '@codesandbox/sandpack-react'; -import {OpenInCodeSandboxButton} from './OpenInCodeSandboxButton'; -import {ResetButton} from './ResetButton'; -import {DownloadButton} from './DownloadButton'; -import {FilesDropdown} from './FilesDropdown'; - -export function NavigationBar({showDownload}: {showDownload: boolean}) { - const {sandpack} = useSandpack(); - const [dropdownActive, setDropdownActive] = React.useState(false); - const {openPaths, clients} = sandpack; - const clientId = Object.keys(clients)[0]; - const {refresh} = useSandpackNavigation(clientId); - - const resizeHandler = React.useCallback(() => { - const width = window.innerWidth || document.documentElement.clientWidth; - if (!dropdownActive && width < 640) { - setDropdownActive(true); - } - if (dropdownActive && width >= 640) { - setDropdownActive(false); - } - }, [dropdownActive]); - - React.useEffect(() => { - if (openPaths.length > 1) { - resizeHandler(); - window.addEventListener('resize', resizeHandler); - return () => { - window.removeEventListener('resize', resizeHandler); - }; - } - return; - }, [openPaths.length, resizeHandler]); - - const handleReset = () => { - sandpack.resetAllFiles(); - refresh(); - }; - - return ( -
-
- {dropdownActive ? : } -
-
- {showDownload && } - - -
-
- ); -} diff --git a/beta/src/components/MDX/Sandpack/Preview.tsx b/beta/src/components/MDX/Sandpack/Preview.tsx deleted file mode 100644 index 232682f3b..000000000 --- a/beta/src/components/MDX/Sandpack/Preview.tsx +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -/* eslint-disable react-hooks/exhaustive-deps */ -import * as React from 'react'; -import {useSandpack, LoadingOverlay} from '@codesandbox/sandpack-react'; -import cn from 'classnames'; - -import {Error} from './Error'; -import {computeViewportSize, generateRandomId} from './utils'; - -type CustomPreviewProps = { - className?: string; - customStyle?: Record; - isExpanded: boolean; -}; - -function useDebounced(value: any): any { - const ref = React.useRef(null); - const [saved, setSaved] = React.useState(value); - React.useEffect(() => { - clearTimeout(ref.current); - ref.current = setTimeout(() => { - setSaved(value); - }, 300); - }, [value]); - return saved; -} - -export function Preview({ - customStyle, - isExpanded, - className, -}: CustomPreviewProps) { - const {sandpack, listen} = useSandpack(); - const [isReady, setIsReady] = React.useState(false); - const [iframeComputedHeight, setComputedAutoHeight] = React.useState< - number | null - >(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; - } - // It changes too fast, causing flicker. - const error = useDebounced(rawError); - - const clientId = React.useRef(generateRandomId()); - const iframeRef = React.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; - - React.useEffect(function createBundler() { - const iframeElement = iframeRef.current!; - registerBundler(iframeElement, clientId.current); - - return () => { - unregisterBundler(clientId.current); - }; - }, []); - - React.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 viewportStyle = computeViewportSize('auto', 'portrait'); - 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/pages/blog/2013/07/11/react-v0-4-prop-validation-and-default-values.md b/beta/src/pages/blog/2013/07/11/react-v0-4-prop-validation-and-default-values.md deleted file mode 100644 index 59a41733c..000000000 --- a/beta/src/pages/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/pages/blog/2013/07/17/react-v0-4-0.md b/beta/src/pages/blog/2013/07/17/react-v0-4-0.md deleted file mode 100644 index 65a730234..000000000 --- a/beta/src/pages/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 ``, ` -``` - -In React, a `` 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 [`