Ein Überblick über Render Props in React
Die Verwendung von Render Props in React ist eine Technik zur effizienten Wiederverwendung von Code. Laut der React-Dokumentation „nimmt eine Komponente mit einer Render-Prop eine Funktion entgegen, die ein React-Element zurückgibt, und ruft diese auf, anstatt ihre eigene Render-Logik zu implementieren.“ Um zu verstehen, was das bedeutet, betrachten wir das Render-Props-Muster und wenden es dann auf ein paar einfache Beispiele an.
Das Render-Props-Muster
Bei der Arbeit mit Render Props übergibt man eine Render-Funktion an eine Komponente, die wiederum ein React-Element zurückgibt. Diese Render-Funktion wird von einer anderen Komponente definiert, und die empfangende Komponente teilt, was über die Render-Funktion übergeben wird.
So sieht das aus
class BaseComponent extends Component {
render() {
return <Fragment>{this.props.render()}</Fragment>;
}
}
Stellen Sie sich vor, unsere App ist eine Geschenkbox, und die App selbst ist die Schleife obendrauf. Wenn die Box die Komponente ist, die wir erstellen, und wir sie öffnen, legen wir die Props, Zustände, Funktionen und Methoden frei, die benötigt werden, um die Komponente funktionsfähig zu machen, sobald sie von render() aufgerufen wird.

Die Render-Funktion einer Komponente enthält normalerweise das gesamte JSX und dergleichen, das das DOM für diese Komponente bildet. Stattdessen hat diese Komponente eine Render-Funktion, this.props.render(), die eine Komponente anzeigt, die über Props übergeben wird.
Beispiel: Erstellen eines Zählers
Siehe den Pen React Render Props von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.
Erstellen wir ein einfaches Zählerbeispiel, das einen Wert je nach angeklicktem Button erhöht und verringert.
Zuerst erstellen wir eine Komponente, die verwendet wird, um den Anfangszustand, die Methoden und das Rendering zu umschließen. Kreativerweise nennen wir sie Wrapper
class Wrapper extends Component {
state = {
count: 0
};
// Increase count
increment = () => {
const { count } = this.state;
return this.setState({ count: count + 1 });
};
// Decrease count
decrement = () => {
const { count } = this.state;
return this.setState({ count: count - 1 });
};
render() {
const { count } = this.state;
return (
<div>
{this.props.render({
increment: this.increment,
decrement: this.decrement,
count: count
})}
</div>
);
}
}
In der Wrapper-Komponente geben wir die Methoden und den Zustand an, die der umhüllten Komponente zur Verfügung gestellt werden. Für dieses Beispiel benötigen wir die Methoden increment und decrement. Unser Standardwert für count ist 0. Die Logik besteht darin, count je nach ausgelöster Methode zu erhöhen oder zu verringern, beginnend mit einem Nullwert.
Wenn Sie sich die Methode return() ansehen, werden Sie feststellen, dass wir this.props.render() verwenden. Durch diese Funktion übergeben wir Methoden und Zustand von der Wrapper-Komponente, damit die von ihr umhüllte Komponente sie nutzen kann.
Um sie für unsere App-Komponente zu verwenden, sieht die Komponente wie folgt aus
class App extends React.Component {
render() {
return (
<Wrapper
render={({ increment, decrement, count }) => (
<div>
<div>
<h3>Render Props Counter</h3>
</div>
<div>
<p>{count}</p>
<button onClick={() => increment()}>Increment</button>
<button onClick={() => decrement()}>Decrement</button>
</div>
</div>
)}
/>
);
}
}
Beispiel: Erstellen einer Datenliste
Der Vorteil liegt in der Wiederverwendbarkeit von Render Props. Erstellen wir eine Komponente, die verwendet werden kann, um eine Liste von Daten zu verarbeiten, die von einer API abrufbar sind.
Siehe den Pen React Render Props 2 von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.
Was wollen wir diesmal von der Wrapper-Komponente? Wir wollen ihr den Quelllink für die Daten übergeben, die wir rendern möchten, dann eine GET-Anfrage stellen, um die Daten abzurufen. Sobald die Daten abgerufen wurden, setzen wir sie als neuen Zustand der Komponente und rendern sie zur Anzeige.
class Wrapper extends React.Component {
state = {
isLoading: true,
error: null,
list: []
};
fetchData() {
axios.get(this.props.link)
.then((response) => {
this.setState({
list: response.data,
isLoading: false
});
})
.catch(error => this.setState({ error, isLoading: false }));
}
componentDidMount() {
this.setState({ isLoading: true }, this.fetchData);
}
render() {
return this.props.render(this.state);
}
}
Der Datenlink wird als Props an die Wrapper-Komponente übergeben. Wenn wir die Antwort vom Server erhalten, aktualisieren wir list mit dem, was vom Server zurückgegeben wird. Die Anfrage wird nach dem Mounten der Komponente an den Server gesendet.
So wird die Wrapper verwendet
class App extends React.Component {
render() {
return (
<Wrapper
link="https://jsonplaceholder.typicode.com/users"
render={({ list, isLoading, error }) => (
<div>
<h2>Random Users</h2>
{error ? <p>{error.message}</p> : null}
{isLoading ? (
<h2>Loading...</h2>
) : (
<ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul>
)}
</div>
)}
/>
);
}
}
Sie sehen, dass wir den Link als Prop übergeben und dann ES6-Destrukturierung verwenden, um den Zustand der Wrapper-Komponente zu erhalten, der dann gerendert wird. Beim ersten Laden der Komponente zeigen wir einen Lade-Text an, der durch die Liste der Elemente ersetzt wird, sobald wir eine Antwort und Daten vom Server erhalten.
Die App-Komponente hier ist eine Klassenkomponente, da sie keinen Zustand verwaltet. Wir können sie in eine funktionale zustandslose Komponente umwandeln.
const App = () => {
return (
<Wrapper
link="https://jsonplaceholder.typicode.com/users"
render={({ list, isLoading, error }) => (
<div>
<h2>Random Users</h2>
{error ? <p>{error.message}</p> : null}
{isLoading ? (
<h2>Loading...</h2>
) : (
<ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul>
)}
</div>
)}
/>
);
}
Das ist ein Abschluss!
Leute vergleichen oft Render Props mit Higher-Order Components. Wenn Sie diesen Weg gehen möchten, empfehle ich Ihnen, diesen Beitrag sowie diesen aufschlussreichen Vortrag zu diesem Thema von Michael Jackson anzusehen.
Danke für den Beitrag.
Mir scheint, dass diese Technik nur dann relevant ist, wenn mehrere Präsentationskomponenten die gleiche Logik des Wrappers verwenden könnten. Wenn nur eine Präsentationskomponente wahrscheinlich diese Logik verwenden wird, ergibt die Verwendung der Technik keinen Sinn.
Macht das Sinn?
Können Sie andere Anwendungsfälle dafür vorschlagen?
danke
„Stellen Sie sich vor, unsere App ist eine Geschenkbox, und die App selbst ist die Schleife obendrauf.“ Was ist also die App?