Pouvez-vous forcer un composant React à rediriger sans appeler setState?

J'ai un objet observable externe (au composant) sur lequel je veux écouter les changements. Lorsque l'objet est mis à jour, il émet des événements de modification, puis je veux rediriger le composant lorsqu'un changement est détecté.

Avec un React.render de niveau supérieur, cela a été possible, mais dans un composant, cela ne fonctionne pas (ce qui a du sens puisque la méthode render renvoie juste un objet).

Voici un exemple de code:

export default class MyComponent extends React.Component {

  handleButtonClick() {
    this.render();
  }

  render() {
    return (
      <div>
        {Math.random()}
        <button onClick={this.handleButtonClick.bind(this)}>
          Click me
        </button>
      </div>
    )
  }
}

Cliquer sur le bouton en interne appelle this.render(), mais ce n'est pas ce qui provoque réellement le rendu (vous pouvez le voir en action car le texte créé par {Math.random()} ne change pas). Cependant, si j'appelle simplement this.setState() au lieu de this.render(), cela fonctionne bien.

Donc, je suppose que ma question Est: {[17] } Les composants React ont-ils besoin de d'avoir un État pour rediriger? Existe-t-il un moyen de forcer le composant à se mettre à jour à la demande sans changer d'état?

404
demandé sur Dmitry Shvedov 2015-06-03 19:44:58

14 réponses

Dans votre composant, vous pouvez appeler this.forceUpdate() pour forcer un rerender.

Documentation: https://facebook.github.io/react/docs/component-api.html

504
répondu Crob 2017-04-12 15:42:58

forceUpdate devrait être évité parce qu'il dévie d'un État D'esprit React. Les documents React citent un exemple de quand forceUpdate pourrait être utilisé:

Par défaut, lorsque l'état ou les accessoires de votre composant changent, votre composant sera rendu à nouveau. Cependant, si ceux-ci changent implicitement (par exemple: les données profondes dans un objet changent sans changer l'objet lui-même) ou si votre méthode render() dépend d'autres données, vous pouvez dire à React qu'elle doit relancer render () en appelant forceUpdate ().

Cependant, je voudrais proposer l'idée que même avec des objets profondément imbriqués, forceUpdate est inutile. En utilisant une source de données immuable, le suivi des modifications devient peu coûteux; un changement entraînera toujours un nouvel objet, il suffit donc de vérifier si la référence à l'objet a changé. Vous pouvez utiliser la bibliothèque js immuable pour implémenter des objets de données immuables dans votre application.

, Normalement, vous devriez essayer d'éviter toutes les utilisations de forceUpdate() et seulement lire à partir de ce.des accessoires et de la ce.de l'état dans render(). Cela rend votre composant "pur" et de votre demande beaucoup plus simple et plus efficace. https://facebook.github.io/react/docs/component-api.html#forceupdate

Changer la clé de l'élément que vous voulez restituer fonctionnera. Définissez l'accessoire de clé sur votre élément via state, puis lorsque vous souhaitez mettre à jour set state pour avoir une nouvelle clé.

<Element key={this.state.key} /> 

Ensuite, un changement se produit et vous réinitialisez la clé

this.setState({ key: Math.random() });

Je veux noter que cela remplacera l'élément sur lequel la clé change. Un exemple de cas où cela pourrait être utile, c'est quand vous avez un champ de saisie fichier que vous souhaitez réinitialiser après un téléchargement d'image.

Alors que la vraie réponse à la question de L'OP serait forceUpdate() j'ai trouvé cette solution utile dans différentes situations. Je tiens également à noter que si vous vous trouvez en utilisant forceUpdate, vous voudrez peut-être revoir votre code et voir s'il y a une autre façon de faire les choses.

216
répondu pizza-r0b 2016-09-20 17:43:42

En fait, forceUpdate() est la seule solution correcte car setState() pourrait Pas déclencher un nouveau rendu si une logique supplémentaire est implémentée dans shouldComponentUpdate() ou quand elle renvoie simplement false.

ForceUpdate ()

L'appel de {[0] } entraînera l'appel de render() sur le composant, en ignorant shouldComponentUpdate(). plus...

SetState ()

setState() déclenchera toujours un nouveau rendu à moins que la logique de rendu conditionnelle ne soit implémentée dans shouldComponentUpdate(). plus...


forceUpdate() peut être appelé depuis votre composant par this.forceUpdate()
43
répondu Qwerty 2016-06-02 14:06:02

Lorsque vous voulez que deux composants React communiquent, qui ne sont pas liés par une relation (parent-enfant), il est conseillé d'utiliser Flux ou des architectures similaires.

Ce que vous voulez faire est d'écouter les modifications du magasin composant observable, qui contient le modèle et son interface, et d'enregistrer les données qui font changer le rendu comme state dans MyComponent. Lorsque le magasin pousse les nouvelles données, vous modifiez l'état de votre composant, ce qui se déclenche automatiquement rendu.

Normalement, vous devriez essayer d'éviter d'utiliser forceUpdate() . De la documentation:

Normalement, vous devriez essayer d'éviter toutes les utilisations de forceUpdate() et seulement lire à partir de ceci.des accessoires et de la ce.de l'état dans render(). Cela rend votre application beaucoup plus simple et plus efficace

26
répondu gcedo 2017-11-17 10:54:04

J'ai Évité forceUpdate en suivant

Mauvais sens : n'utilisez pas l'index comme clé

this.state.rows.map((item, index) =>
   <MyComponent cell={item} key={index} />
)

Manière correcte : Utilisez l'id de données comme clé, il peut s'agir d'un guid etc

this.state.rows.map((item) =>
   <MyComponent item={item} key={item.id} />
)

Donc, en faisant une telle amélioration de code, votre composant sera UNIQUE et rendra naturellement

18
répondu vijay 2018-08-26 15:53:46

Donc, je suppose que ma question Est: Les composants React doivent-ils avoir un État dans ordre de réenregistrer? Existe-t-il un moyen de forcer le composant à mettre à jour la demande sans modification de l'état?

Les autres réponses ont essayé d'illustrer comment vous pourriez, mais le fait est que vous ne devriez pas . Même la solution hacky de changer la clé manque le point. Le pouvoir de React abandonne le contrôle de la gestion manuelle quand quelque chose devrait être rendu, et au lieu de cela, juste concernant vous - même avec comment quelque chose devrait mapper sur les entrées. Puis flux d'alimentation des entrées.

Si vous devez forcer manuellement le rendu, vous ne faites presque certainement pas quelque chose de bien.

11
répondu Kyle Baker 2017-01-03 22:02:37

Aucun État ne s'inquiète de rendre à nouveau

Je stockais beaucoup mes données dans l'état quand j'ai commencé à utiliser react en pensant que je devais le faire pour le rendu. C'était très mauvais. Il s'avère que vous pouvez même éviter de faire des choses compliquées comme Flux et Redux si vous roulez des magasins immuables simples.

BaseView classe à hériter et gérer les mises à jour du magasin

import React, { Component } from 'react';
import { View } from 'react-native';

export default class BaseView extends Component {

  constructor(props) {
    super(props)
    this.state = {}
  }

  onChange = () => {
    this.setState(this.state) // dumb easy: triggers render
  }

  componentWillMount = () => {
    this.stores && this.stores.forEach(store => {
      // each store has a common change event to subscribe to
      store.on('change', this.onChange)
    })
  }

  componentWillUnmount = () => {
    this.stores && this.stores.forEach(store => {
      store.off('change', this.onChange)
    })
  }

}

Comment utiliser

import React, { Component } from 'react'
import { View, Text } from 'react-native'
import BaseView from './BaseView'
import myStore from './myStore'

class MyView extends BaseView {
  contructor(props) {
    super(props)
    this.stores = [myStore]
  }

  render() {
    return (<View><Text onPress={() => {
      myStore.update({ message: 'hi' + Date.now() })
    }}>{myStore.get().message}</Text></View>)
  }
}

Simple Magasin Exemple de classe

var ee = require('event-emitter')
export default class Store {
  constructor() {
    this._data = {}
    this._eventEmitter = ee({})
  }
  get() {
    return {...this._data} // immutable
  }
  update(newData) {
    this._data = {..._this.data, ...newData}
    this._eventEmitter.emit('change')
  }
  on(ev, fn) {
    this._eventEmitter.on(ev, fn)
  }
  off(ev, fn) {
    this._eventEmitter.off(ev, fn)
  }
}

Magasin exemple, comme singleton

import Store from './Store'

const myStore = new Store()
export default myStore

Je pense que cela supprime tous les frameworks crufty nécessaires pour les petites applications. Utilisez redux pour les moyennes et grandes mais couplé avec immuable.js.

6
répondu Jason Sebring 2018-03-07 15:49:09

On peut utiliser ça.forceUpdate() comme ci-dessous.

       class MyComponent extends React.Component {



      handleButtonClick = ()=>{
          this.forceUpdate();
     }


 render() {

   return (
     <div>
      {Math.random()}
        <button  onClick={this.handleButtonClick}>
        Click me
        </button>
     </div>
    )
  }
}

 ReactDOM.render(<MyComponent /> , mountNode);

L'Élément ' Math.la partie random' dans le DOM n'est mise à jour que si vous utilisez le setState pour restituer le composant.

Toutes les réponses ici sont correctes complétant la question pour understanding..as nous savons que re-rendre un composant sans utiliser setState ({}) est en utilisant la forceUpdate ().

Le code ci-dessus s'exécute avec setState comme ci-dessous.

 class MyComponent extends React.Component {



             handleButtonClick = ()=>{
                this.setState({ });
              }


        render() {
         return (
  <div>
    {Math.random()}
    <button  onClick={this.handleButtonClick}>
      Click me
    </button>
  </div>
)
  }
 }

ReactDOM.render(<MyComponent /> , mountNode);
5
répondu Dhana 2018-07-06 13:15:57

Vous pourriez le faire de plusieurs façons:

1. Utilisez la méthode forceUpdate():

Certains problèmes peuvent survenir lors de l'utilisation de la méthode forceUpdate(). Un exemple est qu'il ignore la méthode shouldComponentUpdate() et rendra à nouveau la vue indépendamment du fait que shouldComponentUpdate() renvoie false. Pour cette raison, l'utilisation de forceUpdate() doit être évitée lorsque cela est possible.

2. Le passage de cette.État à la méthode setState()

La ligne de code suivante surmonte le problème avec le exemple précédent:

this.setState(this.state);

En réalité, tout cela consiste à écraser l'état actuel avec l'état actuel, ce qui déclenche un nouveau rendu. Ce n'est toujours pas nécessairement la meilleure façon de faire les choses, mais il surmonte certains des problèmes que vous pourriez rencontrer en utilisant la méthode forceUpdate ().

3
répondu kojow7 2017-09-01 23:41:36

J'ai trouvé préférable d'éviter forceUpdate (). Une façon de forcer le re-render est d'ajouter une dépendance de render () sur une variable externe temporaire et de changer la valeur de cette variable au besoin.

Voici un exemple de code:

class Example extends Component{
   constructor(props){
      this.state = {temp:0};

      this.forceChange = this.forceChange.bind(this);
   }

   forceChange(){
      this.setState(prevState => ({
          temp: prevState.temp++
      })); 
   }

   render(){
      return(
         <div>{this.state.temp &&
             <div>
                  ... add code here ...
             </div>}
         </div>
      )
   }
}

Appelez ceci.forceChange () lorsque vous devez forcer le rendu.

0
répondu raksheetbhat 2017-12-26 06:12:35

ES6 - j'inclus un exemple, ce qui m'a été utile:

Dans une "instruction if courte", vous pouvez passer une fonction vide comme ceci:

isReady ? ()=>{} : onClick

Cela semble être l'approche la plus courte.

()=>{}
0
répondu MrDoda 2018-05-30 18:52:46

Une Autre façon est d'appeler setState, ET préserver l'état:

this.setState(prevState=>({...prevState});

0
répondu dbvt10 2018-07-24 11:54:14

forceUpdate(); méthode de travail, mais il est conseillé d'utiliser setState();

0
répondu Chiamaka Ikeanyi 2018-08-21 15:07:23

Afin d'accomplir ce que vous décrivez, essayez ceci.forceUpdate ().

0
répondu API-Andy 2018-09-18 14:17:01