web-dev-qa-db-fra.com

réagit la différence de routeur entre composant et rendu

Je ne comprends vraiment pas la différence entre le rendu et le composant prop dans Route dans le routeur de réaction. Dans la documentation, il est indiqué que le rendu ne crée pas de nouvel élément, mais le composant le fait. J'ai essayé de revenir en arrière avec l'historique, mais j'ai trouvé que composantWillMount était appelé utilisez render dans Route, que veulent-ils dire par "si vous fournissez une fonction en ligne à l'attribut composant, vous créerez un nouveau composant à chaque rendu. Le démontage du composant existant et le montage du nouveau composant au lieu de simplement mettre à jour le composant existant . "

36
scully

Le code source indique la différence:

if (component)
  return match ? React.createElement(component, props) : null

if (render)
  return match ? render(props) : null

Lorsque vous utilisez component prop, le composant est instancié à chaque appel de Route#render. Cela signifie que, pour votre composant que vous passez à component prop de Route, le constructeur, componentWillMount et componentDidMount seront exécutés à chaque rendu de la route.

Par exemple, si vous avez

<Route path="/:locale/store" component={Store} />

et l'utilisateur navigue vers/en/store, puis ailleurs, puis de nouveau dans/en/store, le composant Store sera monté, puis démonté, puis à nouveau monté. C'est comme faire

<Route path="/:locale/store">
  <Store />
</Route>

Par rapport à cela, si vous utilisez render prop, le composant est évalué sur chaque Route#render. Rappelez-vous que chaque composant est une fonction? Cette fonction sera exécutée telle quelle, sans aucune méthode de cycle de vie. Alors quand tu l'as comme

<Route path="/:locale/store" render={Store} />

vous pouvez penser à cela

<Route path="/:locale/store">
  {Store()}
</Route>

Cela vous permet d'économiser du temps d'exécution, car aucune méthode de cycle de vie n'est exécutée, mais présente également des inconvénients si le composant Store possède des méthodes de cycle de vie post-montage telles que shouldComponentUpdate qui peuvent également améliorer les performances.


Il y avait n bon post sur Medium à propos de cette performance , jetez-y un coup d'œil. C'est très bien écrit et est applicable à React 16, aussi.

47
Fleischpflanzerl

Donc, je suis confus sur cette section de la documentation aussi, mais je l'ai finalement compris.

La clé pour comprendre ceci est la déclaration "fournit une fonction inline au composant prop"

Nous savons tous que le composant Route sera rendu de nouveau lorsque l'emplacement changera et que Comparary comparera l'ancien et le nouvel arbre DOM virtuel, obtiendra un résultat diff et s'appliquera au vrai DOM.

Et réagissez, essayez de réutiliser le nœud DOM, à moins que le type type ou clé du nouveau ReactElement ne soit modifié.

Alors

// 1.
const componentA = React.createElement(App, props)
const componentB = React.createElement(App, props)
console.log(componentA.type === componentB.type)             // true

// 2.
const componentA = React.createElement(() => <App />, props)
const componentB = React.createElement(() => <App />, props)
console.log(componentA.type === componentB.type)             // false

Tous les ReactElements créés par le moyen 1 ont le même type (composant d'application), mais ils n'ont pas le même type s'ils sont tous créés par le moyen 2.

Pourquoi?

Comme il y a toujours une nouvelle fonction anonyme créée de la manière 2 lorsque la méthode de rendu du composant parent (le composant qui contient le composant Route) est invoquée, le type de new & old ReactElement est deux instances différentes de la méthode anonyme. une fonction

() => <App />

Donc, du point de vue de React, il existe différents types d'élément et doit être traité avec l'opération démonter l'ancien> mount new, cela signifie que chaque état ou modification apportée à l'ancien composant est perdue à chaque fois que le composant parent -rendre.

Mais pourquoi l’accessoire de rendu évite-t-il le comportement de démontage et montage? C'est une fonction anonyme aussi !?

Je voudrais ici faire référence au code que @Rishat Muhametshin a posté, la partie essentielle de la méthode de rendu du composant Route:

if (component)
  // We already know the differences:
  // React.createElement(component)
  // React.createElement(() => <component/>)
  return match ? React.createElement(component, props) : null

if (render)
  return match ? render(props) : null

render prop est une fonction qui renvoie un ReactElement lorsqu’elle est appelée, quel est le type de cet élément retourné?

<Route render={() => <AppComponent />}></Route>

C'est AppComponent, pas l'encapsuleur de fonction anonyme! Parce qu'après jsx compilé:

render = () => React.createElement(AppComponent)
render() = React.createElement(AppComponent)

React.createElement(render) =
  React.createElement(() => React.createElement(AppComponent))

React.createElement(render()) =
  React.createElement(React.createElement(AppComponent))

Ainsi, lorsque vous utilisez render au lieu de prop, le type d'élément renvoyé par la fonction render prop ne changera pas à chaque rendu, même s'il existe toujours une nouvelle instance de fonction anonyme créée sur chaque parentElement.render ().

De mon point de vue, vous pouvez obtenir le même comportement que celui que rend rend prop avec composant prop en nommant la fonction anonyme:

// Put this line outside render method.
const CreateAppComponent = () => <AppComponent />

// Inside render method
render(){
  return <Route component={CreateAppComponent}/>
}

La conclusion est donc qu'il n'y a pas de performance différente entre composant et rendu prop si vous utilisez directement composant = {AppComponent}, si vous souhaitez attribuer des propriétés à AppComponent, utilisez render={() => <AppComponent {...props}/> } au lieu de component={() => <AppComponent {...props}/> }

26
ilovezcd

La plupart des concepts ont été expliqués par d'autres réponses. Permettez-moi de résoudre le problème en procédant comme suit:

Tout d’abord, nous avons code source :

if (component)
  return match ? React.createElement(component, props) : null

if (render)
  return match ? render(props) : null

cas n ° 1: composant sans fonction

<Route path="/create" component={CreatePage} />

React.createElement(CreatePage, props) être appelé en raison de React.createElement(component, props) à partir du code source. L'instanciation provoquerait un remontage .

cas n ° 2: rendu sans fonction

<Route path="/create" render={CreatePage} />

React.createElement(CreatePage, props) a été appelé avant de passer à l’application de rendu, puis appelé par render(props) à partir du code source. Pas d'instanciation, pas de remontée.

cas n ° 3: composant avec fonction

<Route path="/create" component={ () => <CreatePage /> } />

React.createElement(CreatePage, props) être appelé deux fois . Premièrement pour l'analyse jsx (fonction anonyme), d'abord pour renvoyer une instance de CreatePage à partir d'une fonction anonyme, ensuite pour le code source. Alors, pourquoi ne pas le faire dans le composant prop.

Les erreurs indiquent par oligofren :

L'analyse du JSX ne l'appelle pas. Il finit par créer l'expression de la fonction. La raison pour laquelle vous ne voulez pas faire # 3 est que vous créez un nouveau type anonyme à chaque fois, ce qui provoque le remontage du dom.

cas n ° 4: rendu avec fonction

<Route path="/create" render={ () => <CreatePage /> } />

Il y a une instanciation (analyse jsx) à chaque fois lors du routage vers path=/create. Vous sentez-vous comme le cas n ° 1 ?

Conclusion

Selon les quatre cas, si nous voulons passer prop à Component, nous devons utiliser le cas # 4 pour empêcher le remontage.

<Route path="/abc" render={()=><TestWidget num="2" someProp={100}/>}/>

Ceci est un peu éloigné du sujet, je laisse donc la discussion officielle pour plus de lecture.

9
Tokenyet

Même si nous ne passons aucun accessoire à ComponentToRender, j'ai trouvé des avantages à utiliser rend au lieu de composant. Par défaut <Route \> passer des accessoires supplémentaires ({ history, location, match }) à ComponentToRender lors de l'utilisation de composant. Nous pouvons accéder à ces accessoires via le callback rend, mais nous pouvons également l'omettre. Pourquoi en avons-nous besoin? Chaque rendu de <Route />'s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\_\_\_\n\n de la même manière que précédemment, créez un nouvel objet match. Ainsi, lorsque nous le transmettrons à notre ComponentToRender, nous aurons à chaque fois de nouveaux accessoires, ce qui peut entraîner des problèmes de performances, en particulier avec PureComponent.

1
cutscenedev