Skip to content

Commit

Permalink
Merge pull request #623 from reactjs/sync-6bfde58c
Browse files Browse the repository at this point in the history
Sync with react.dev @ 6bfde58
  • Loading branch information
tdd authored Jan 15, 2024
2 parents 7821f08 + 0eb6645 commit dd9b03c
Show file tree
Hide file tree
Showing 21 changed files with 551 additions and 153 deletions.
16 changes: 9 additions & 7 deletions src/components/DocsFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const DocsPageFooter = memo<DocsPageFooterProps>(
<>
{prevRoute?.path || nextRoute?.path ? (
<>
<div className="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-4 py-4 md:py-12">
<div className="grid grid-cols-1 gap-4 py-4 mx-auto max-w-7xl md:grid-cols-2 md:py-12">
{prevRoute?.path ? (
<FooterLink
type="Previous"
Expand Down Expand Up @@ -69,21 +69,23 @@ function FooterLink({
<NextLink
href={href}
className={cn(
'flex gap-x-4 md:gap-x-6 items-center w-full md:w-80 px-4 md:px-5 py-6 border-2 border-transparent text-base leading-base text-link dark:text-link-dark rounded-lg group focus:text-link dark:focus:text-link-dark focus:bg-highlight focus:border-link dark:focus:bg-highlight-dark dark:focus:border-link-dark focus:border-opacity-100 focus:border-2 focus:ring-1 focus:ring-offset-4 focus:ring-blue-40 active:ring-0 active:ring-offset-0 hover:bg-gray-5 dark:hover:bg-gray-80',
'flex gap-x-4 md:gap-x-6 items-center w-full md:min-w-80 md:w-fit md:max-w-md px-4 md:px-5 py-6 border-2 border-transparent text-base leading-base text-link dark:text-link-dark rounded-lg group focus:text-link dark:focus:text-link-dark focus:bg-highlight focus:border-link dark:focus:bg-highlight-dark dark:focus:border-link-dark focus:border-opacity-100 focus:border-2 focus:ring-1 focus:ring-offset-4 focus:ring-blue-40 active:ring-0 active:ring-offset-0 hover:bg-gray-5 dark:hover:bg-gray-80',
{
'flex-row-reverse justify-self-end text-end': type === 'Next',
}
)}>
<IconNavArrow
className="text-tertiary dark:text-tertiary-dark inline group-focus:text-link dark:group-focus:text-link-dark"
className="inline text-tertiary dark:text-tertiary-dark group-focus:text-link dark:group-focus:text-link-dark"
displayDirection={type === 'Previous' ? 'start' : 'end'}
/>
<span>
<span className="block no-underline text-sm tracking-wide text-secondary dark:text-secondary-dark uppercase font-bold group-focus:text-link dark:group-focus:text-link-dark group-focus:text-opacity-100">
<div className="flex flex-col overflow-hidden">
<span className="text-sm font-bold tracking-wide no-underline uppercase text-secondary dark:text-secondary-dark group-focus:text-link dark:group-focus:text-link-dark group-focus:text-opacity-100">
{type === 'Next' ? 'Suivant' : 'Précédent'}
</span>
<span className="block text-lg group-hover:underline">{title}</span>
</span>
<span className="text-lg break-words group-hover:underline">
{title}
</span>
</div>
</NextLink>
);
}
23 changes: 23 additions & 0 deletions src/components/ErrorDecoderContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Error Decoder requires reading pregenerated error message from getStaticProps,
// but MDX component doesn't support props. So we use React Context to populate
// the value without prop-drilling.
// TODO: Replace with React.cache + React.use when migrating to Next.js App Router

import {createContext, useContext} from 'react';

const notInErrorDecoderContext = Symbol('not in error decoder context');

export const ErrorDecoderContext = createContext<
| {errorMessage: string | null; errorCode: string | null}
| typeof notInErrorDecoderContext
>(notInErrorDecoderContext);

export const useErrorDecoderParams = () => {
const params = useContext(ErrorDecoderContext);

if (params === notInErrorDecoderContext) {
throw new Error('useErrorDecoder must be used in error decoder pages only');
}

return params;
};
7 changes: 6 additions & 1 deletion src/components/Layout/Feedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import {useState} from 'react';
import {useRouter} from 'next/router';
import cn from 'classnames';

export function Feedback({onSubmit = () => {}}: {onSubmit?: () => void}) {
const {asPath} = useRouter();
Expand Down Expand Up @@ -60,7 +61,11 @@ function sendGAEvent(isPositive: boolean) {
function SendFeedback({onSubmit}: {onSubmit: () => void}) {
const [isSubmitted, setIsSubmitted] = useState(false);
return (
<div className="max-w-xs w-80 lg:w-auto py-3 shadow-lg rounded-lg m-4 bg-wash dark:bg-gray-95 px-4 flex">
<div
className={cn(
'max-w-xs w-80 lg:w-auto py-3 shadow-lg rounded-lg m-4 bg-wash dark:bg-gray-95 px-4 flex',
{exit: isSubmitted}
)}>
<p className="w-full font-bold text-primary dark:text-primary-dark text-lg me-4">
{isSubmitted ? 'Merci pour votre retour !' : 'Cette page est utile ?'}
</p>
Expand Down
107 changes: 107 additions & 0 deletions src/components/MDX/ErrorDecoder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import {useEffect, useState} from 'react';
import {useErrorDecoderParams} from '../ErrorDecoderContext';
import cn from 'classnames';

function replaceArgs(
msg: string,
argList: Array<string | undefined>,
replacer = '[missing argument]'
): string {
let argIdx = 0;
return msg.replace(/%s/g, function () {
const arg = argList[argIdx++];
// arg can be an empty string: ?args[0]=&args[1]=count
return arg === undefined || arg === '' ? replacer : arg;
});
}

/**
* Sindre Sorhus <https://sindresorhus.com>
* Released under MIT license
* https://github.com/sindresorhus/linkify-urls/blob/edd75a64a9c36d7025f102f666ddbb6cf0afa7cd/index.js#L4C25-L4C137
*
* The regex is used to extract URL from the string for linkify.
*/
const urlRegex =
/((?<!\+)https?:\/\/(?:www\.)?(?:[-\w.]+?[.@][a-zA-Z\d]{2,}|localhost)(?:[-\w.:%+~#*$!?&/=@]*?(?:,(?!\s))*?)*)/g;

// When the message contains a URL (like https://fb.me/react-refs-must-have-owner),
// make it a clickable link.
function urlify(str: string): React.ReactNode[] {
const segments = str.split(urlRegex);

return segments.map((message, i) => {
if (i % 2 === 1) {
return (
<a
key={i}
target="_blank"
className="underline"
rel="noopener noreferrer"
href={message}>
{message}
</a>
);
}
return message;
});
}

// `?args[]=foo&args[]=bar`
// or `// ?args[0]=foo&args[1]=bar`
function parseQueryString(search: string): Array<string | undefined> {
const rawQueryString = search.substring(1);
if (!rawQueryString) {
return [];
}

const args: Array<string | undefined> = [];

const queries = rawQueryString.split('&');
for (let i = 0; i < queries.length; i++) {
const query = decodeURIComponent(queries[i]);
if (query.startsWith('args[')) {
args.push(query.slice(query.indexOf(']=') + 2));
}
}

return args;
}

export default function ErrorDecoder() {
const {errorMessage} = useErrorDecoderParams();
/** error messages that contain %s require reading location.search */
const hasParams = errorMessage?.includes('%s');
const [message, setMessage] = useState<React.ReactNode | null>(() =>
errorMessage ? urlify(errorMessage) : null
);

const [isReady, setIsReady] = useState(errorMessage == null || !hasParams);

useEffect(() => {
if (errorMessage == null || !hasParams) {
return;
}

setMessage(
urlify(
replaceArgs(
errorMessage,
parseQueryString(window.location.search),
'[missing argument]'
)
)
);
setIsReady(true);
}, [hasParams, errorMessage]);

return (
<code
className={cn(
'block bg-red-100 text-red-600 py-4 px-6 mt-5 rounded-lg',
isReady ? 'opacity-100' : 'opacity-0'
)}>
<b>{message}</b>
</code>
);
}
3 changes: 3 additions & 0 deletions src/components/MDX/MDXComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {TocContext} from './TocContext';
import type {Toc, TocItem} from './TocContext';
import {TeamMember} from './TeamMember';

import ErrorDecoder from './ErrorDecoder';

function CodeStep({children, step}: {children: any; step: number}) {
return (
<span
Expand Down Expand Up @@ -441,6 +443,7 @@ export const MDXComponents = {
Solution,
CodeStep,
YouTubeIframe,
ErrorDecoder,
};

for (let key in MDXComponents) {
Expand Down
12 changes: 11 additions & 1 deletion src/content/community/conferences.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Vous connaissez une conférence React.js locale ? Ajoutez-la ! (Merci de conse

## Conférences à venir {/*upcoming-conferences*/}

### React Paris 2024 {/*react-paris-2024*/}
March 22, 2024. In-person in Paris, France + Remote (hybrid)

[Site web](https://react.paris/) - [Twitter](https://twitter.com/BeJS_) - [LinkedIn](https://www.linkedin.com/events/7150816372074192900/comments/)

### App.js Conf 2024 {/*appjs-conf-2024*/}
May 22 - 24, 2024. In-person in Kraków, Poland + remote

Expand All @@ -20,6 +25,11 @@ June 12 - June 14, 2024. Atlanta, GA, USA

[Site web](https://renderatl.com) - [Discord](https://www.renderatl.com/discord) - [Twitter](https://twitter.com/renderATL) - [Instagram](https://www.instagram.com/renderatl/) - [Facebook](https://www.facebook.com/renderatl/) - [LinkedIn](https://www.linkedin.com/company/renderatl) - [Podcast](https://www.renderatl.com/culture-and-code#/)

### React Nexus 2024 {/*react-nexus-2024*/}
July 04 & 05, 2024. Bangalore, India (In-person event)

[Site web](https://reactnexus.com/) - [Twitter](https://twitter.com/ReactNexus) - [Linkedin](https://www.linkedin.com/company/react-nexus) - [YouTube](https://www.youtube.com/reactify_in)

### React India 2024 {/*react-india-2024*/}
October 17 - 19, 2024. In-person in Goa, India (hybrid event) + Oct 15 2024 - remote day

Expand Down Expand Up @@ -50,7 +60,7 @@ October 20 & 23, 2023. In-person in London, UK + remote first interactivity (hyb
### React Brussels 2023 {/*react-brussels-2023*/}
October 13th 2023. In-person in Brussels, Belgium + Remote (hybrid)

[Site web](https://www.react.brussels/) - [Twitter](https://twitter.com/BrusselsReact)
[Site web](https://www.react.brussels/) - [Twitter](https://twitter.com/BrusselsReact) - [Vidéos](https://www.youtube.com/playlist?list=PL53Z0yyYnpWh85KeMomUoVz8_brrmh_aC)

### React India 2023 {/*react-india-2023*/}
October 5 - 7, 2023. In-person in Goa, India (hybrid event) + Oct 3 2023 - remote day
Expand Down
10 changes: 6 additions & 4 deletions src/content/community/meetups.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ Vous connaissez un meetup React.js local ? Ajoutez-le ! (Merci de conserver un
* [Karlsruhe](https://www.meetup.com/react_ka/)
* [Kiel](https://www.meetup.com/Kiel-React-Native-Meetup/)
* [Munich](https://www.meetup.com/ReactJS-Meetup-Munich/)
* [React Berlin](https://www.meetup.com/React-Open-Source/)
* [React Berlin](https://guild.host/react-berlin)

## Angleterre (R.-U.) {/*england-uk*/}
* [Manchester](https://www.meetup.com/Manchester-React-User-Group/)
* [React.JS Girls London](https://www.meetup.com/ReactJS-Girls-London/)
* [React London : Bring Your Own Project](https://www.meetup.com/React-London-Bring-Your-Own-Project/)
* [React Advanced London](https://guild.host/react-advanced-london)
* [React Native London](https://guild.host/RNLDN)

## Argentine {/*argentina*/}
* [Buenos Aires](https://www.meetup.com/es/React-en-Buenos-Aires)
Expand Down Expand Up @@ -117,6 +118,7 @@ Vous connaissez un meetup React.js local ? Ajoutez-le ! (Merci de conserver un
* [New York, NY - React Ladies](https://www.meetup.com/React-Ladies/)
* [New York, NY - React Native](https://www.meetup.com/React-Native-NYC/)
* [New York, NY - useReactNYC](https://www.meetup.com/useReactNYC/)
* [New York, NY - React.NYC](https://guild.host/react-nyc)
* [Omaha, NE - ReactJS/React Native](https://www.meetup.com/omaha-react-meetup-group/)
* [Palo Alto, CA - React Native](https://www.meetup.com/React-Native-Silicon-Valley/)
* [Philadelphia, PA - ReactJS](https://www.meetup.com/Reactadelphia/)
Expand Down Expand Up @@ -162,7 +164,7 @@ Vous connaissez un meetup React.js local ? Ajoutez-le ! (Merci de conserver un
* [Indonesia](https://www.meetup.com/reactindonesia/)

## Irlande {/*ireland*/}
* [Dublin](https://www.meetup.com/ReactJS-Dublin/)
* [Dublin](https://guild.host/reactjs-dublin)

## Israël {/*israel*/}
* [Tel Aviv](https://www.meetup.com/ReactJS-Israel/)
Expand Down Expand Up @@ -192,7 +194,7 @@ Vous connaissez un meetup React.js local ? Ajoutez-le ! (Merci de conserver un
* [Panama](https://www.meetup.com/React-Panama/)

## Pays-Bas {/*netherlands*/}
* [Amsterdam](https://www.meetup.com/React-Amsterdam/)
* [Amsterdam](https://guild.host/react-amsterdam)

## Pérou {/*peru*/}
* [Lima](https://www.meetup.com/ReactJS-Peru/)
Expand Down
13 changes: 13 additions & 0 deletions src/content/errors/377.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Intro>

Dans le *build* de production minifié de React, nous évitons d'inclure les messages d'erreur complets afin de réduire le nombre d'octets transmis sur le réseau.

</Intro>

Nous vous recommandons fortement d'utiliser le *build* de développement en local lorsque vous déboguez votre appli, dans la mesure où il fournit des informations de débogage supplémentaires et des avertissements utiles sur des problèmes potentiels dans vos applis, mais si vous rencontrez une exception en utilisant le *build* de production, cette page reconstruira le message d'erreur original.

Le texte complet de l'erreur que vous venez de rencontrer est le suivant :

<ErrorDecoder />

Cette erreur survient lorsque vous passez une valeur `BigInt` depuis un Composant Serveur vers un Composant Client.
11 changes: 11 additions & 0 deletions src/content/errors/generic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Intro>

Dans le *build* de production minifié de React, nous évitons d'inclure les messages d'erreur complets afin de réduire le nombre d'octets transmis sur le réseau.

</Intro>

Nous vous recommandons fortement d'utiliser le *build* de développement en local lorsque vous déboguez votre appli, dans la mesure où il fournit des informations de débogage supplémentaires et des avertissements utiles sur des problèmes potentiels dans vos applis, mais si vous rencontrez une exception en utilisant le *build* de production, cette page reconstruira le message d'erreur original.

Le texte complet de l'erreur que vous venez de rencontrer est le suivant :

<ErrorDecoder />
9 changes: 9 additions & 0 deletions src/content/errors/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Intro>

Dans le *build* de production minifié de React, nous évitons d'inclure les messages d'erreur complets afin de réduire le nombre d'octets transmis sur le réseau.

</Intro>

Nous vous recommandons fortement d'utiliser le *build* de développement en local lorsque vous déboguez votre appli, dans la mesure où il fournit des informations de débogage supplémentaires et des avertissements utiles sur des problèmes potentiels dans vos applis, mais si vous rencontrez une exception en utilisant le *build* de production, le message d'erreur incluera un lien vers la documentation pour cette erreur.

À titre d'exemple, consultez : [https://fr.react.dev/errors/421](/errors/421).
1 change: 0 additions & 1 deletion src/content/learn/updating-arrays-in-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,6 @@ Par exemple :
```js
import { useState } from 'react';

let nextId = 3;
const initialList = [
{ id: 0, title: 'Big Bellies' },
{ id: 1, title: 'Lunar Landscape' },
Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react/forwardRef.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const MyInput = forwardRef(function MyInput(props, ref) {

#### Limitations {/*caveats*/}

* En Mode Strict, React **appellera votre fonction composant deux fois** afin de [vous aider à repérer des impuretés accidentelles](#my-initializer-or-updater-function-runs-twice). Ce comportement est limité au développement et n'affecte pas la production. Une des valeurs renvoyées sera ignorée. Si votre fonction composant est pure (ce qui devrait être le cas), ça n'affectera en rien son comportement.
* En Mode Strict, React **appellera votre fonction composant deux fois** afin de [vous aider à repérer des impuretés accidentelles](/reference/react/useState#my-initializer-or-updater-function-runs-twice). Ce comportement est limité au développement et n'affecte pas la production. Une des valeurs renvoyées sera ignorée. Si votre fonction composant est pure (ce qui devrait être le cas), ça n'affectera en rien son comportement.

---

Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react/useContext.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ function LoginForm() {
const {setCurrentUser} = useContext(CurrentUserContext);
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const canLogin = firstName !== '' && lastName !== '';
const canLogin = firstName.trim() !== '' && lastName.trim() !== '';
return (
<>
<label>
Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react/useRef.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Lors des rendus ultérieurs, `useRef` renverra le même objet.
* Vous pouvez modifier la propriété `ref.current`. Contrairement à l'état, elle est modifiable. En revanche, si vous y stockez un objet nécessaire au rendu (par exemple un morceau de votre état), vous ne devriez pas modifier cet objet.
* Lorsque vous modifiez la propriété `ref.current`, React ne refait pas de rendu de votre composant. React n'est pas au courant de vos modifications parce qu'une ref est un objet JavaScript brut.
* Évitez d'écrire _ou même de lire_ `ref.current` lors du rendu, sauf pour [l'initialiser](#avoiding-recreating-the-ref-contents). Ça rendrait le comportement de votre composant imprévisible.
* En Mode Strict, React **appellera votre fonction composant deux fois** afin de [vous aider à repérer des impuretés accidentelles](#my-initializer-or-updater-function-runs-twice). Ce comportement est limité au développement et n'affecte pas la production. Chaque objet ref sera créé deux fois, mais une de ses versions sera ignorée. Si votre fonction composant est pure (ce qui devrait être le cas), ça n'affectera en rien son comportement.
* En Mode Strict, React **appellera votre fonction composant deux fois** afin de [vous aider à repérer des impuretés accidentelles](/reference/react/useState#my-initializer-or-updater-function-runs-twice). Ce comportement est limité au développement et n'affecte pas la production. Chaque objet ref sera créé deux fois, mais une de ses versions sera ignorée. Si votre fonction composant est pure (ce qui devrait être le cas), ça n'affectera en rien son comportement.
---
Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react/useState.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ title: useState
`useState` est un Hook React qui ajoute une [variable d'état](/learn/state-a-components-memory) dans votre composant.

```js
const [state, setState] = useState(initialState);
const [state, setState] = useState(initialState)
```

</Intro>
Expand Down
Loading

0 comments on commit dd9b03c

Please sign in to comment.