Résumé des points clés
Si vous avez déjà fait une page de base de l'application React, il peut avoir de mauvais problèmes de référencement et de performances, en particulier sur des appareils plus lents. Vous pouvez ajouter un rendu de serveur Web traditionnel (généralement à l'aide de NodeJS), mais ce n'est pas un processus facile, surtout lorsqu'il s'agit de API asynchrones.
Les deux principaux avantages du code de rendu côté serveur sont:
N'oubliez pas que Google attendra que votre JavaScript se charge, donc un contenu simple tel que le contenu de titre changera sans problèmes. (Je ne peux pas dire ce qui se passe avec d'autres moteurs de recherche, cependant, ou à quel point cela est fiable.)
Dans cet article, je vais discuter de la façon d'obtenir des données d'une API asynchrone lors de l'utilisation du code de réaction rendu du serveur. React Code a une structure d'application entière intégrée à JavaScript. Cela signifie que contrairement au mode MVC traditionnel avec les contrôleurs, vous ne savez pas quelles données vous avez besoin avant que l'application ne rende. Avec un cadre comme Create React App, vous pouvez rapidement créer des applications de travail de haute qualité, mais cela vous oblige à gérer le rendu uniquement du côté client. Cela a des problèmes de performances, ainsi que des problèmes de référencement / données, où vous pouvez modifier l'en-tête au besoin.
Question
réagir principalement synchronise le rendu, donc si vous n'avez pas de données, l'écran de chargement sera rendu et en attente de l'arrivée des données. Cela ne fonctionne pas bien du côté serveur parce que vous ne savez pas ce dont vous avez besoin avant de vous rendre, ou vous savez ce dont vous avez besoin, mais vous l'avez rendu.
Afficher cette méthode de rendu standard:
ReactDOM.render( <provider> store={store}></provider> <browserrouter></browserrouter> <app></app> > > , document.getElementById('root') )
Question:
donc j'ai utilisé deux bibliothèques ici et elles sont très populaires, donc j'espère qu'elle peut être appliquée aux autres bibliothèques que vous utilisez.
redux: L'état du serveur de stockage et la synchronisation des clients sont un problème de cauchemar. Il est très cher et conduit souvent à des erreurs complexes. Du côté du serveur, idéalement, vous ne voulez rien faire avec Redux, sauf qu'il suffit de faire fonctionner les choses et de rendre correctement. (Vous pouvez toujours l'utiliser comme d'habitude; définissez simplement l'état suffisant pour le faire ressembler à un client.) Si vous voulez l'essayer, consultez les différents guides système distribués comme point de départ.
React-Router: FYI, c'est la version V4, qui est la version installée par défaut, mais elle sera très différente si vous avez un projet existant plus ancien. Vous devez vous assurer de gérer le routage du côté serveur et du côté client et d'utiliser V4 - c'est excellent à cet égard.
Après tout, que se passe-t-il si vous avez besoin de passer un appel de base de données? Cela devient soudainement un gros problème car il est asynchrone et est situé à l'intérieur de votre composant. Bien sûr, ce n'est pas une nouvelle question: le voir dans le référentiel officiel React.
Vous devez rendre pour déterminer les dépendances nécessaires - ces dépendances doivent être déterminées au moment de l'exécution et pour obtenir ces dépendances avant d'être fournies au client.
Solutions existantes
ci-dessous, je reviendrai les solutions actuellement fournies pour ce problème.
Avant de commencer, Suivant.js est idéal pour vous si vous souhaitez que le code réactif est rendu côté serveur ou une application universelle pour votre environnement de production. Il est efficace, concis et a un support Zeit.
Cependant, il est opiniâtre, vous devez utiliser leur chaîne d'outils, et la façon dont ils gèrent le chargement de données asynchrone n'est pas nécessairement si flexible.
Affichez cette copie directe du contenu dans le document de référentiel suivant:
ReactDOM.render( <provider> store={store}></provider> <browserrouter></browserrouter> <app></app> > > , document.getElementById('root') )
getInitialProps
est la clé, elle renvoie une promesse qui se résout à un objet rempli d'accessoires et n'est que sur la page. Mieux encore, cela est juste intégré à leur chaîne d'outils: ajoutez-le au travail sans aucun travail!
Alors, comment obtenir des données de base de données? Vous faites un appel API. Tu ne veux pas? Ok, c'est horrible. (D'accord, vous pouvez ajouter du contenu personnalisé, mais vous devez l'implémenter complètement vous-même.) Cependant, si vous y réfléchissez, c'est une pratique très raisonnable et généralement bonne car sinon, votre client sera toujours les mêmes appels API Et la latence sur le serveur est presque négligeable.
Ce que vous pouvez également accéder est limité - presque juste l'objet de demande; Oh, et si vous ne l'avez pas remarqué auparavant, cela ne fonctionne qu'avec des composants de page de niveau supérieur.
Redux Connect est un rendu côté serveur très opiniâtre avec une bonne idée, mais ce n'est peut-être pas pour vous si vous n'utilisez pas tous les outils qu'ils décrivent. Ce package a beaucoup de contenu, mais il est très complexe et n'a pas été mis à niveau pour React Router V4. Il existe de nombreux paramètres, mais regardons la partie la plus importante, juste pour apprendre quelques leçons:
ReactDOM.render( <provider> store={store}></provider> <browserrouter></browserrouter> <app></app> > > , document.getElementById('root') )
Les décorateurs ne sont pas standard en JavaScript. Au moment de la rédaction du moment de la rédaction, ils sont dans la phase 2, alors utilisez avec prudence. C'est juste une autre façon d'ajouter des composants d'ordre supérieur. L'idée est simple: la clé est ce qui est passé à vos accessoires, puis vous avez une série de promesses qui analyseront et passeront. Cela a l'air bien. Peut-être qu'une autre option est la suivante:
import React from 'react' export default class extends React.Component { static async getInitialProps ({ req }) { return req ? { userAgent: req.headers['user-agent'] } : { userAgent: navigator.userAgent } } render () { return <div> Hello World {this.props.userAgent} </div> } }
Cela peut être fait avec JavaScript sans trop de problèmes.
Le référentiel React-frontload n'a pas beaucoup de documentation ou d'explications, mais la meilleure compréhension que je puisse obtenir peut provenir des tests (comme celui-ci) et de la lecture du code source. Lorsque quelque chose est monté, il est ajouté à la file d'attente de promesses, et lorsque la file d'attente est analysée, elle est servie. Ce qu'il fait est très bien, bien qu'il soit difficile de recommander quelque chose qui n'est pas bien documenté, entretenu ou utilisé:
// 1. 连接您的数据,类似于 react-redux @connect @asyncConnect([{ key: 'lunch', promise: ({ params, helpers }) => Promise.resolve({ id: 1, name: 'Borsch' }) }]) class App extends React.Component { render() { // 2. 将数据作为 props 访问 const lunch = this.props.lunch return ( <div>{lunch.name}</div> ) } }
à la recherche de meilleures solutions
Aucune des solutions ci-dessus ne correspond vraiment à mes attentes pour la flexibilité et la simplicité de la bibliothèque, donc je vais maintenant présenter ma propre implémentation. L'objectif n'est pas d'écrire des packages, mais de vous donner une idée de la façon d'écrire vos propres packages en fonction de votre cas d'utilisation.
Le référentiel de cet exemple de solution est situé ici.
L'idée derrière elle est relativement simple, bien qu'elle finisse par produire beaucoup de code. Il s'agit de décrire les idées dont nous discutons.
Le serveur doit rendre le code réact deux fois, et nous n'utiliserons que renderToString
pour cela. Nous voulons garder le contexte entre les premier et deuxième rendus. Dans notre premier rendu, nous avons essayé d'éliminer tous les appels, promesses et opérations asynchrones. Dans notre deuxième rendu, nous voulons prendre toutes les données que nous obtenons et la remettre dans notre contexte, en rendant notre page de travail pour la distribution. Cela signifie également que le code d'application doit effectuer des actions en fonction du contexte (ou non des opérations d'exécution), par exemple s'il est sur le serveur ou sur le navigateur, et dans les deux cas si les données sont récupérées.
De plus, nous pouvons le personnaliser au besoin. Dans ce cas, nous modifions le code d'état et l'en-tête en fonction du contexte.
Dans votre code, vous devez savoir si vous travaillez sur le serveur ou sur le navigateur, idéalement, vous voulez avoir un contrôle complexe dessus. Avec React Router, vous pouvez obtenir un accessoire de contexte statique, ce qui est génial, nous allons donc l'utiliser. Actuellement, nous ajoutons simplement un objet de données et demandons des données, comme nous l'avons appris de Next.js. Nos API varient entre le serveur et le client, vous devez donc fournir une API de serveur qui est préférable d'avoir une interface similaire à votre API client:
ReactDOM.render( <provider> store={store}></provider> <browserrouter></browserrouter> <app></app> > > , document.getElementById('root') )
Après le premier rendu, nous obtiendrons ces promesses en attente et attendrons que ces promesses se terminent, puis renforcent, mettant à jour le contexte:
import React from 'react' export default class extends React.Component { static async getInitialProps ({ req }) { return req ? { userAgent: req.headers['user-agent'] } : { userAgent: navigator.userAgent } } render () { return <div> Hello World {this.props.userAgent} </div> } }
Passez rapidement de notre serveur vers le code d'application: Dans n'importe lequel de nos composants avec des connexions de routeur, nous pouvons l'obtenir maintenant:
// 1. 连接您的数据,类似于 react-redux @connect @asyncConnect([{ key: 'lunch', promise: ({ params, helpers }) => Promise.resolve({ id: 1, name: 'Borsch' }) }]) class App extends React.Component { render() { // 2. 将数据作为 props 访问 const lunch = this.props.lunch return ( <div>{lunch.name}</div> ) } }
wow, il y a beaucoup de code compliqué. À ce stade, vous voudrez peut-être adopter une approche plus relayée où vous séparez le code de récupération des données dans un autre composant.
Ce composant se compose de composants que vous connaissez peut-être - des étapes de rendu et componentWillMount
. Les instructions IF en quatre étapes gèrent différents états: rendu post-fetch, post-rendu et back-end. Nous ajoutons également les données à l'en-tête une fois qu'elle est chargée.
Enfin, il y a une autre étape pour obtenir les données. Idéalement, votre API et votre base de données ont la même API, ce qui rend l'exécution la même. Vous voudrez peut-être les mettre dans des actions dans Thunk ou Saga pour les rendre plus évolutives.
Affichez l'article "REACTER REACT SERVER" et le rendu du serveur React Reactory pour plus d'informations. N'oubliez pas que vous devez toujours gérer l'état où les données ne sont pas chargées! Vous ne ferez un rendu côté serveur que lorsque le premier chargement, vous afficherez donc l'écran de chargement sur les pages suivantes.
Nous devons envoyer des données préfabriquées dans le cadre de la demande de page, nous ajouterons donc une balise de script:
@asyncConnect([{ lunch: ({ params, helpers }) => Promise.resolve({ id: 1, name: 'Borsch' }) }])
Ensuite, nous devons l'ajouter à notre recherche et à notre remplacement. Cependant, HTML utilise un chercheur de balises de script très basique, donc si vous avez des balises de script, vous avez besoin de la base-64 encodant. Aussi, n'oubliez pas nos étiquettes de tête!
const App = () => ( <frontload>isServer</frontload> <component1> entityId='1' store={store}></component1> > ) return frontloadServerRender(() => ( render(<app></app>) )).then((serverRenderedMarkup) => { console.log(serverRenderedMarkup) })
Nous gérons également les modifications du code d'état - par exemple, pour 404 - donc si vous avez une page 404, vous pouvez le faire:
const context = {data: {}, head: [], req, api} const store = configureStore() renderToString( <provider> store={store}></provider> <staticrouter> location={req.url} context={context}> <app></app> > > )
Résumé
Si vous n'êtes pas sûr de ce que vous faites, utilisez simplement Next.js. Il est conçu pour le rendu côté serveur et les applications universelles, ou si vous voulez que la flexibilité fasse tout manuellement, vous pouvez le faire comme vous le souhaitez. Un exemple peut vous inclure de faire des données en train de récupérer dans un composant enfant plutôt qu'au niveau de la page.
J'espère que cet article pourra vous aider à démarrer! N'oubliez pas de consulter le référentiel GitHub pour une implémentation viable.
FAQS (FAQ) sur les API asynchrones et le rendu de côté du serveur React
Le rendu côté serveur (SSR) et le rendu côté client (CSR) sont deux façons différentes de rendre les pages Web. Dans SSR, le serveur génère le HTML complet de la page en réponse à la demande, puis l'envoie au client. Il en résulte des temps de chargement initiaux plus rapides et est bénéfique pour le référencement. Cependant, cela peut faire en sorte que la conversion de la page soit plus lente, car la page entière doit être rendue à chaque demande. CSR, en revanche, signifie que le rendu se fait dans le navigateur à l'aide de JavaScript. Cela fait ralentir le temps de chargement de la page initiale, mais la conversion de la page est plus rapide car seuls les composants nécessaires doivent être renvoyés.
Pour faire des demandes côté serveur dans une application REACT renvoyée côté client, vous pouvez utiliser des bibliothèques telles que API Fetch ou Axios. Vous pouvez faire une demande dans la méthode du cycle de vie componentDidMount
ou dans le crochet useEffect
lors de l'utilisation du composant de fonction. La réponse peut ensuite être définie sur l'état et utilisé dans votre composant.
Cela peut être dû à la façon dont les mises à jour de l'état de lots réagissent. Si vous mettez à jour les variables globales dans un composant React, il peut être mis à jour deux fois en raison de la nature asynchrone de setState
. Pour éviter cela, vous pouvez utiliser la forme de fonction de setState
, qui garantit que la mise à jour de l'état est basée sur l'état précédent, et non sur l'état actuel.
Pour utiliser l'API asynchrone dans la réaction rendue côté serveur, vous pouvez utiliser la syntaxe async/await
dans le code côté serveur. Cela vous permet d'attendre la réponse de l'API avant de rendre la page. Vous pouvez utiliser des bibliothèques telles que Axios pour faire des demandes d'API.
Le rendu côté serveur présente de nombreux avantages en réaction. Il améliore le temps de chargement des pages initial, ce qui peut conduire à une meilleure expérience utilisateur. Il améliore également le référencement car les robots des moteurs de recherche peuvent indexer plus facilement le contenu rendu côté serveur. De plus, il permet un état initial plus cohérent, car le même code s'exécute sur le serveur et le client.
Vous pouvez utiliser le bloc try/catch
pour gérer les erreurs dans une fonction asynchrone. Cela vous permet de capturer toutes les erreurs qui se produisent lors de la création de demandes d'API et de les gérer de manière appropriée, par exemple en rendant les messages d'erreur.
Oui, vous pouvez utiliser des crochets dans React rendu du serveur. Cependant, n'oubliez pas que les crochets ne peuvent être utilisés que dans les composants de la fonction, pas dans les composants de la classe. De plus, certains crochets (par exemple useEffect
) ne s'exécuteront pas sur le serveur, vous devez donc vous assurer que votre code peut gérer cette situation.
Il existe de nombreuses façons d'améliorer les performances des applications React pour le rendu des serveurs. Vous pouvez utiliser la segmentation du code pour charger uniquement le code nécessaire pour chaque page. Vous pouvez également utiliser le cache pour éviter la rediffusion des pages inchangées. De plus, l'optimisation du code côté serveur peut aider à améliorer les performances.
Vous pouvez utiliser des bibliothèques de tests telles que la bibliothèque de tests et de réaction pour tester vos applications React rendues côté serveur. Ces bibliothèques vous permettent d'isoler les composants de test et de vous assurer qu'ils rendent correctement.
Oui, Next.js est un framework pour React qui prend en charge le rendu de la boîte. Il fournit une simple API de rendu côté serveur et prend également en charge la génération de sites statique et le rendu client.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!