Reagieren - Wie erzwinge ich das Rendern einer Funktionskomponente?

86

Ich habe eine Funktionskomponente und möchte sie zum erneuten Rendern zwingen.

Wie kann ich das machen?
Da es keine Instanz gibt this, kann ich nicht anrufen this.forceUpdate().

Gorakh Nath
quelle
Nein, eine zustandslose Komponente hat keinen Status. Verwenden Sie stattdessen eine Klasse
TryingToImprove
2
Meinen Sie wirklich "zustandslose Komponente " und nicht "funktionale Komponente" ?
Chris
2
Um eine zustandslose Komponente zu aktualisieren, müssen die übergebenen Requisiten geändert werden.
Pilzanthrax
Neben Requisiten können Sie hook useState verwenden, und Komponenten werden bei Änderungen neu gerendert
Hamid Shoja,

Antworten:

134

🎉 Sie können jetzt React Hooks verwenden

Mit React Hooks können Sie jetzt useState()Ihre Funktionskomponente aufrufen .

useState()gibt ein Array von 2 Dingen zurück:
1. Ein Wert, der den aktuellen Status darstellt.
2. Sein Setter. Verwenden Sie diese Option, um den Wert zu aktualisieren.

Den Wert durch seine Setter Aktualisierung wird Ihre Funktion Komponente zwingen, wieder zu machen ,
wie forceUpdatetut:

import React, { useState } from 'react';

//create your forceUpdate hook
function useForceUpdate(){
    const [value, setValue] = useState(0); // integer state
    return () => setValue(value => ++value); // update the state to force render
}

function MyComponent() {
    // call your hook here
    const forceUpdate = useForceUpdate();

    return (
        <div>
            {/*Clicking on the button will force to re-render like force update does */}
            <button onClick={forceUpdate}>
                Click to re-render
            </button>
        </div>
    );
}

Eine Demo finden Sie hier .

Die obige Komponente verwendet eine benutzerdefinierte Hook-Funktion ( useForceUpdate), die einen booleschen Status-Hook ( useState) verwendet. Es schaltet den booleschen Status um und weist React an, die Renderfunktion erneut auszuführen.

BEARBEITEN

In einer alten Version dieser Antwort verwendete das Snippet einen booleschen Wert und schaltete ihn ein forceUpdate(). Nachdem ich meine Antwort bearbeitet habe, verwendet das Snippet eine Zahl anstelle eines Booleschen Werts.

Warum ? (Du würdest mich fragen)

Denn einmal ist es mir passiert, dass my forceUpdate()von zwei verschiedenen Ereignissen zweimal aufgerufen wurde und somit den booleschen Wert auf seinen ursprünglichen Zustand zurückgesetzt hat und die Komponente nie gerendert wurde.

Denn im useStateSetter des S ( setValuehier) Reactvergleichen Sie den vorherigen Status mit dem neuen und rendern nur, wenn der Status anders ist.

Yairopro
quelle
3
Nichts auf dieser Seite enthält Informationen zur Verwendung von Hooks zum Aufrufen forceUpdate.
Jdelman
1
Im Moment haben Sie Recht, es ist besser, denn selbst wenn noch keine harten Hooks veröffentlicht wurden, können Sie es in der Beta verwenden. Aber sobald sie veröffentlicht sind, gibt es keinen Grund, warum die Klassenkomponente besser sein wird. Die Verwendung von Hooks macht Code sauberer als Klassenkomponenten, wie das Video unten in der Reactconf zeigt. Wie auch immer, die Frage ist, ob dies möglich ist. Die Antwort ändert sich jetzt aufgrund von Hooks von "Nein" zu "Ja". youtube.com/watch?v=wXLf18DsV-I
Yairopro
1
Hallo @DanteTheSmith. Mit "Top Level" bedeutet dies, dass Hooks nicht aus einer Bedingung oder Schleife heraus aufgerufen werden dürfen, wie Sie sagten. Aber ich kann Ihnen sagen, dass Sie sie von einer anderen Funktion aus aufrufen können. Und das bedeutet, einen benutzerdefinierten Hook zu erstellen. Dan Abramov, der React-Hooks in der React conf vorstellt, zeigt deutlich, dass dies der sauberste und beste Weg ist, Logik zwischen Funktionskomponenten zu teilen: youtu.be/dpw9EHDh2bM?t=2753
Yairopro
1
Es ist nicht erforderlich, einen Status umzuschalten, um das Rendern zu erzwingen. Sie erzeugen den falschen Eindruck, dass React die Werte für den vorherigen und den nächsten Status "vergleicht", um zu entscheiden, ob es erneut gerendert werden muss. Während es definitiv nicht tut.
Meandre
1
@meandre Ja, es ist definitiv vergleichbar. Wir sprechen über den useStateHook, nicht über die Klasse ', setStatedie in der Tat keinen Vergleich durchführt (es sei denn, Sie implementieren die shouldUpdate-Methode). Siehe die gleiche Demo, die ich gepostet habe, aber mit einem statischen Wert, der für verwendet wird setState, wird sie nicht erneut gerendert
Yairopro
47

Update reagieren v16.8 (16. Februar 2019 Veröffentlichung)

Seit React 16.8 mit Hooks freigegeben wurde , können Funktionskomponenten nun dauerhaft gehalten werden state. Mit dieser Fähigkeit können Sie jetzt Mimik ein forceUpdate:

Beachten Sie, dass dieser Ansatz überdacht werden sollte und in den meisten Fällen, wenn Sie ein Update erzwingen müssen, wahrscheinlich etwas falsch gemacht wird.


Vor der Reaktion 16.8.0

Nein , Sie können nicht, Staat-Less Funktionskomponenten sind nur normal , functionsdass die Renditen jsx, Sie haben keinen Zugriff auf die Lebenszyklus - Methoden reagieren , da Sie nicht von der Verlängerung sind React.Component.

Stellen Sie sich die Funktionskomponente als renderMethodenteil der Klassenkomponenten vor.

Sagiv bg
quelle
ofc du kannst. Ändern Sie die Requisiten, die dazu kommen
Marián Zeke Šedaj
5
Das erzwingt kein erneutes Rendern, das ist nur ein normales Rendern. Wenn Sie das Rendern erzwingen möchten , ist dies normalerweise der Fall, wenn Sie die Rendermethode ausführen möchten, wenn sie nicht für die Ausführung ausgelegt ist, z. B. wenn keine neuen propsoder stateÄnderungen vorhanden sind. Sie können die Renderfunktion nicht erzwingen, da renderfür zustandslose Komponenten keine Funktion vorhanden ist . zustandslose Komponenten sind nicht extends React.Componentnur einfache Funktionen, die zurückgegeben werden jsx.
Sagiv bg
Requisiten für "Wenn Sie ein Update erzwingen müssen, machen Sie wahrscheinlich etwas falsch" - Ich wusste, dass dies der Fall war, aber dies veranlasste mich nur, mir meinen useEffect-Hook noch einmal genauer anzusehen.
Methodiker
12

In den offiziellen FAQ ( https://reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate ) wird diese Methode jetzt empfohlen, wenn Sie dies wirklich tun müssen:

  const [ignored, forceUpdate] = useReducer(x => x + 1, 0);

  function handleClick() {
    forceUpdate();
  }
Gramotei
quelle
Nun, ich habe es nie gewusst
Charith Jayasanka
9
und Sie können Ihren Code 7 Bytes kürzer machen und keine unbenutzten Variablen erstellen:const [, forceUpdate] = useReducer(x => x + 1, 0);
Konstantin Smolyanin
7

Ich habe eine Drittanbieter-Bibliothek namens use-force-update verwendet , um das Rendern meiner reaktionsfähigen Funktionskomponenten zu erzwingen. Arbeitete wie Charme. Verwenden Sie einfach das Paket in Ihr Projekt importieren und verwenden Sie es so.

import useForceUpdate from 'use-force-update';

const MyButton = () => {

  const forceUpdate = useForceUpdate();

  const handleClick = () => {
    alert('I will re-render now.');
    forceUpdate();
  };

  return <button onClick={handleClick} />;
};
Charith Jayasanka
quelle
2
Um Ihnen einen Klick zu ersparen - useForceUpdateverwendet useCallbackwie in anderen Antworten erwähnt. Diese Bibliothek ist nur eine Dienstprogrammbibliothek, mit der Sie nur wenige Tastenanschläge speichern können.
Asyncwait
Oh danke. Das wusste ich nicht. :)
Charith Jayasanka
6

Haftungsausschluss: KEINE ANTWORT AUF DAS PROBLEM.

Hinterlassen Sie hier einen wichtigen Hinweis:

Wenn Sie versuchen, eine zustandslose Komponente zu erzwingen, stimmt möglicherweise etwas mit Ihrem Design nicht.

Betrachten Sie die folgenden Fälle:

  1. Übergeben Sie einen Setter (setState) an eine untergeordnete Komponente, die den Status ändern und die übergeordnete Komponente erneut rendern kann.
  2. Betrachten Sie den Hebezustand
  3. Überlegen Sie, ob Sie diesen Status in Ihren Redux-Speicher einfügen möchten, damit verbundene Komponenten automatisch neu gerendert werden können.
Ankan-Zerob
quelle
1
Ich habe einen Fall, in dem ich die Komponentenaktualisierungen deaktivieren und erzwingen musste, wann immer ich wollte (ist ein sich bewegendes Lineal, das seinen Wert bei jeder Bewegung aktualisiert und die Aktualisierungen verursachten ein flackerndes Verhalten). Daher habe ich mich für die Verwendung von Klassen für diese Komponente entschieden und empfehle, dass alle Komponenten, die eine gründliche Kontrolle des Renderverhaltens benötigen, in Klassen ausgeführt werden, da Hooks derzeit keine genaue Kontrolle über dieses Verhalten bieten. (die aktuelle React-Version ist 16.12)
Michael Wallace
Ich dachte das gleiche, aber ich wollte eine schnelle Lösung, also benutzte ich Force Update.
Charith Jayasanka
In der realen Welt gibt es Verwendungen dafür. Nichts ist jemals perfekt, und wenn Sie jemals Software herausbringen möchten, wissen Sie besser, wie Sie Dinge geschehen lassen können, wenn jemand anderes sie vermasselt.
Brain2000
1

Dies kann ohne explizite Verwendung von Hooks erfolgen, vorausgesetzt, Sie fügen Ihrer Komponente eine Requisite und der übergeordneten Komponente der zustandslosen Komponente einen Status hinzu:

const ParentComponent = props => {
  const [updateNow, setUpdateNow] = useState(true)

  const updateFunc = () => {
    setUpdateNow(!updateNow)
  }

  const MyComponent = props => {
    return (<div> .... </div>)
  }

  const MyButtonComponent = props => {
    return (<div> <input type="button" onClick={props.updateFunc} />.... </div>)
  }

  return (
    <div> 
      <MyComponent updateMe={updateNow} />
      <MyButtonComponent updateFunc={updateFunc}/>
    </div>
  )
}
Charles Goodwin
quelle
1

Die akzeptierte Antwort ist gut. Nur um es verständlicher zu machen.

Beispielkomponente:

export default function MyComponent(props) {

    const [updateView, setUpdateView] = useState(0);

    return (
        <>
            <span style={{ display: "none" }}>{updateView}</span>
        </>
    );
}

Rufen Sie den folgenden Code auf, um ein erneutes Rendern zu erzwingen:

setUpdateView((updateView) => ++updateView);
Manohar Reddy Poreddy
quelle