diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 83e7f2e8a..09b20a00c 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -84,6 +84,7 @@ jobs: - name: Upload analysis comment uses: actions/upload-artifact@v4 + if: success() && github.event.number with: name: analysis_comment.txt path: .next/analyze/__bundle_analysis_comment.txt diff --git a/.github/workflows/analyze_comment.yml b/.github/workflows/analyze_comment.yml index 1e086b9b7..d43380ba8 100644 --- a/.github/workflows/analyze_comment.yml +++ b/.github/workflows/analyze_comment.yml @@ -12,8 +12,8 @@ jobs: comment: runs-on: ubuntu-latest if: > - ${{ github.event.workflow_run.event == 'pull_request' && - github.event.workflow_run.conclusion == 'success' }} + 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 diff --git a/.github/workflows/discord_notify_utlc.yml b/.github/workflows/discord_notify_utlc.yml new file mode 100644 index 000000000..ada464d64 --- /dev/null +++ b/.github/workflows/discord_notify_utlc.yml @@ -0,0 +1,24 @@ +# Discord notify for a Ukrainian community--UTLC (#react-docs-alert channel) +name: Discord Notify + +on: + pull_request_target: + types: [closed, opened, reopened, ready_for_review] + +permissions: {} + +jobs: + notify: + if: github.repository == 'reactjs/uk.react.dev' + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action (UTLC) + uses: tsickert/discord-webhook@v6.0.0 + with: + webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL_UTLC }} + 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/postcss.config.js b/postcss.config.js index 427294522..d55c43c90 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -17,4 +17,4 @@ module.exports = { }, }, }, -} +}; diff --git a/public/js/jsfiddle-integration-babel.js b/public/js/jsfiddle-integration-babel.js index 006c79c8a..56059472f 100644 --- a/public/js/jsfiddle-integration-babel.js +++ b/public/js/jsfiddle-integration-babel.js @@ -4,12 +4,14 @@ // Do not delete or move this file. // Many fiddles reference it so we have to keep it here. -(function() { +(function () { var tag = document.querySelector( 'script[type="application/javascript;version=1.7"]' ); if (!tag || tag.textContent.indexOf('window.onload=function(){') !== -1) { - alert('Bad JSFiddle configuration, please fork the original React JSFiddle'); + alert( + 'Bad JSFiddle configuration, please fork the original React JSFiddle' + ); } tag.setAttribute('type', 'text/babel'); tag.textContent = tag.textContent.replace(/^\/\/ Checks all files and causes an error if heading ID is missing * yarn lint-heading-ids --fix --> Fixes all markdown file's heading IDs * yarn lint-heading-ids path/to/markdown.md --> Checks that particular file for missing heading ID (path can denote a directory or particular file) * yarn lint-heading-ids --fix path/to/markdown.md --> Fixes that particular file's markdown IDs (path can denote a directory or particular file) -*/ + */ const markdownPaths = process.argv.slice(2); if (markdownPaths.includes('--fix')) { diff --git a/src/components/MDX/ErrorDecoder.tsx b/src/components/MDX/ErrorDecoder.tsx index b04fa9f79..a9b7455df 100644 --- a/src/components/MDX/ErrorDecoder.tsx +++ b/src/components/MDX/ErrorDecoder.tsx @@ -69,7 +69,7 @@ function parseQueryString(search: string): Array { } export default function ErrorDecoder() { - const {errorMessage} = useErrorDecoderParams(); + const {errorMessage, errorCode} = useErrorDecoderParams(); /** error messages that contain %s require reading location.search */ const hasParams = errorMessage?.includes('%s'); const [message, setMessage] = useState(() => @@ -82,23 +82,28 @@ export default function ErrorDecoder() { if (errorMessage == null || !hasParams) { return; } + const args = parseQueryString(window.location.search); + let message = errorMessage; + if (errorCode === '418') { + // Hydration errors have a %s for the diff, but we don't add that to the args for security reasons. + message = message.replace(/%s$/, ''); - setMessage( - urlify( - replaceArgs( - errorMessage, - parseQueryString(window.location.search), - '[missing argument]' - ) - ) - ); + // Before React 19.1, the error message didn't have an arg, and was always HTML. + if (args.length === 0) { + args.push('HTML'); + } else if (args.length === 1 && args[0] === '') { + args[0] = 'HTML'; + } + } + + setMessage(urlify(replaceArgs(message, args, '[missing argument]'))); setIsReady(true); - }, [hasParams, errorMessage]); + }, [errorCode, hasParams, errorMessage]); return ( {message} diff --git a/src/components/MDX/Sandpack/template.ts b/src/components/MDX/Sandpack/template.ts index 42f02f6a6..7fbd537e7 100644 --- a/src/components/MDX/Sandpack/template.ts +++ b/src/components/MDX/Sandpack/template.ts @@ -28,8 +28,8 @@ root.render( eject: 'react-scripts eject', }, dependencies: { - react: '19.0.0-rc-3edc000d-20240926', - 'react-dom': '19.0.0-rc-3edc000d-20240926', + react: '^19.1.0', + 'react-dom': '^19.1.0', 'react-scripts': '^5.0.0', }, }, diff --git a/src/content/community/meetups.md b/src/content/community/meetups.md index b3290a004..186740341 100644 --- a/src/content/community/meetups.md +++ b/src/content/community/meetups.md @@ -81,7 +81,7 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Thessaloniki](https://www.meetup.com/Thessaloniki-ReactJS-Meetup/) ## India {/*india*/} -* [Ahmedabad](https://www.meetup.com/react-ahmedabad/) +* [Ahmedabad](https://reactahmedabad.dev/) * [Bangalore (React)](https://www.meetup.com/ReactJS-Bangalore/) * [Bangalore (React Native)](https://www.meetup.com/React-Native-Bangalore-Meetup) * [Chennai](https://www.linkedin.com/company/chennaireact) @@ -169,6 +169,7 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Cleveland, OH - ReactJS](https://www.meetup.com/Cleveland-React/) * [Columbus, OH - ReactJS](https://www.meetup.com/ReactJS-Columbus-meetup/) * [Dallas, TX - ReactJS](https://www.meetup.com/ReactDallas/) +* [Denver, CO - React Denver](https://reactdenver.com/) * [Detroit, MI - Detroit React User Group](https://www.meetup.com/Detroit-React-User-Group/) * [Indianapolis, IN - React.Indy](https://www.meetup.com/React-Indy) * [Irvine, CA - ReactJS](https://www.meetup.com/ReactJS-OC/) diff --git a/src/content/learn/build-a-react-app-from-scratch.md b/src/content/learn/build-a-react-app-from-scratch.md index 76057c2c1..e54063903 100644 --- a/src/content/learn/build-a-react-app-from-scratch.md +++ b/src/content/learn/build-a-react-app-from-scratch.md @@ -83,7 +83,7 @@ Rsbuild відразу підтримує такі функції React, як ш Пропонуємо використовувати: -- [React Router](https://reactrouter.com/start/framework/custom) +- [React Router](https://reactrouter.com/start/data/custom) - [Tanstack Router](https://tanstack.com/router/latest) diff --git a/src/content/learn/describing-the-ui.md b/src/content/learn/describing-the-ui.md index 95073027c..0ef0c125d 100644 --- a/src/content/learn/describing-the-ui.md +++ b/src/content/learn/describing-the-ui.md @@ -230,7 +230,7 @@ body > div > div { padding: 20px; } -Прочитайте розділ **["JavaScript у JSX з фігурними дужками"](/learn/javascript-in-jsx-with-curly-braces)**, щоб дізнатися, як отримувати доступ до JavaScript-елементів зсередини JSX. +Прочитайте розділ **["JavaScript у JSX із фігурними дужками"](/learn/javascript-in-jsx-with-curly-braces)**, щоб дізнатися, як отримувати доступ до JavaScript-елементів зсередини JSX. diff --git a/src/content/learn/reusing-logic-with-custom-hooks.md b/src/content/learn/reusing-logic-with-custom-hooks.md index 67de5e97f..ea8d0a313 100644 --- a/src/content/learn/reusing-logic-with-custom-hooks.md +++ b/src/content/learn/reusing-logic-with-custom-hooks.md @@ -1333,7 +1333,7 @@ export function useOnlineStatus() { In the above example, `useOnlineStatus` is implemented with a pair of [`useState`](/reference/react/useState) and [`useEffect`.](/reference/react/useEffect) However, this isn't the best possible solution. There is a number of edge cases it doesn't consider. For example, it assumes that when the component mounts, `isOnline` is already `true`, but this may be wrong if the network already went offline. You can use the browser [`navigator.onLine`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) API to check for that, but using it directly would not work on the server for generating the initial HTML. In short, this code could be improved. -Luckily, React 18 includes a dedicated API called [`useSyncExternalStore`](/reference/react/useSyncExternalStore) which takes care of all of these problems for you. Here is how your `useOnlineStatus` Hook, rewritten to take advantage of this new API: +React includes a dedicated API called [`useSyncExternalStore`](/reference/react/useSyncExternalStore) which takes care of all of these problems for you. Here is your `useOnlineStatus` Hook, rewritten to take advantage of this new API: diff --git a/src/content/learn/tutorial-tic-tac-toe.md b/src/content/learn/tutorial-tic-tac-toe.md index aae421835..ab4d5aff3 100644 --- a/src/content/learn/tutorial-tic-tac-toe.md +++ b/src/content/learn/tutorial-tic-tac-toe.md @@ -2247,7 +2247,7 @@ body { -As you iterate through `history` array inside the function you passed to `map`, the `squares` argument goes through each element of `history`, and the `move` argument goes through each array index: `0`, `1`, `2`, …. (In most cases, you'd need the actual array elements, but to render a list of moves you will only need indexes.) +As you iterate through the `history` array inside the function you passed to `map`, the `squares` argument goes through each element of `history`, and the `move` argument goes through each array index: `0`, `1`, `2`, …. (In most cases, you'd need the actual array elements, but to render a list of moves you will only need indexes.) For each move in the tic-tac-toe game's history, you create a list item `
  • ` which contains a button `; @@ -417,22 +379,6 @@ export default function App() { } ``` -```json package.json hidden -{ - "dependencies": { - "react": "canary", - "react-dom": "canary", - "react-scripts": "latest" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" - } -} -``` - ### `captureOwnerStack` is not available {/*captureownerstack-is-not-available*/} diff --git a/src/content/reference/react/useSyncExternalStore.md b/src/content/reference/react/useSyncExternalStore.md index 05e0c0831..ce989a2a4 100644 --- a/src/content/reference/react/useSyncExternalStore.md +++ b/src/content/reference/react/useSyncExternalStore.md @@ -405,14 +405,14 @@ If your store data is mutable, your `getSnapshot` function should return an immu This `subscribe` function is defined *inside* a component so it is different on every re-render: -```js {4-7} +```js {2-5} function ChatIndicator() { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); - // 🚩 Always a different function, so React will resubscribe on every re-render function subscribe() { // ... } + + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } @@ -420,28 +420,28 @@ function ChatIndicator() { React will resubscribe to your store if you pass a different `subscribe` function between re-renders. If this causes performance issues and you'd like to avoid resubscribing, move the `subscribe` function outside: -```js {6-9} -function ChatIndicator() { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); +```js {1-4} +// ✅ Always the same function, so React won't need to resubscribe +function subscribe() { // ... } -// ✅ Always the same function, so React won't need to resubscribe -function subscribe() { +function ChatIndicator() { + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } ``` Alternatively, wrap `subscribe` into [`useCallback`](/reference/react/useCallback) to only resubscribe when some argument changes: -```js {4-8} +```js {2-5} function ChatIndicator({ userId }) { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); - // ✅ Same function as long as userId doesn't change const subscribe = useCallback(() => { // ... }, [userId]); + + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } diff --git a/src/pages/errors/[errorCode].tsx b/src/pages/errors/[errorCode].tsx index de9eab5bb..a67c5742d 100644 --- a/src/pages/errors/[errorCode].tsx +++ b/src/pages/errors/[errorCode].tsx @@ -36,7 +36,7 @@ export default function ErrorDecoderPage({ }} routeTree={sidebarLearn as RouteItem} section="unknown"> -
    {parsedContent}
    +
    {parsedContent}
    {/*

    We highly recommend using the development build locally when debugging diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 2c3d63dc1..7de4f166f 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -117,6 +117,9 @@ { "title": "cache", "path": "/reference/react/cache" + }, { + "title": "captureOwnerStack", + "path": "/reference/react/captureOwnerStack" }, { "title": "createContext", @@ -147,11 +150,6 @@ "title": "experimental_taintUniqueValue", "path": "/reference/react/experimental_taintUniqueValue", "version": "canary" - }, - { - "title": "captureOwnerStack", - "path": "/reference/react/captureOwnerStack", - "version": "canary" } ] }, diff --git a/src/siteConfig.js b/src/siteConfig.js index 59348c878..ee1e6a2cb 100644 --- a/src/siteConfig.js +++ b/src/siteConfig.js @@ -2,7 +2,7 @@ * Copyright (c) Facebook, Inc. and its affiliates. */ exports.siteConfig = { - version: '19', + version: '19.1', // -------------------------------------- // Translations should replace these lines: languageCode: 'uk',