In einem früheren Beitrag haben wir gesehen, wie man den Zustand mit Unstated verwaltet. Wie Sie sich vielleicht erinnern, verwendet Unstated Reacts eingebautes setState, um Komponenten zu erstellen, die den Zustand verbrauchen können, indem sie sich an einen Provider abonnieren – wie die Context API von React.
Nun werden wir auf dem letzten Beitrag aufbauen und uns Unstated Next ansehen, eine Bibliothek, die der Autor Jamie Kyle als "spirituellen Nachfolger" seines Unstated-Projekts bezeichnet. Unstated Next bietet sowohl React Hooks als auch die Context API zur Verwaltung des Zustands. Unstated war eine minimale Abstraktion der Idee von React Hooks, bevor diese voll ausgereift waren. Aber jetzt, da Hooks in React so gut sind, ist diese Abstraktion unnötig und Unstated Next integriert sie einfach, während es eine API zum Teilen von Zustand und Logik mit den Hooks bereitstellt.
Wir werden uns speziell ansehen, wie der Zustand in einzelnen und mehreren Komponenten mit Unstated Next verwaltet wird. Es kann hilfreich sein, den vorherigen Beitrag zu Unstated zu lesen, bevor Sie fortfahren, aber es ist nicht unbedingt notwendig.
Beispiel: Eine minimale Formular-Komponente
Zunächst erstellen wir eine winzige React-Anwendung für ein Formular, das lediglich ein Textfeld für den Namen einer Person und einen Button zum Absenden enthält. Wenn der Button geklickt wird, zeigen wir den Namen als Absatz oberhalb des Formulars an. Der Quellcode für dieses Beispiel ist auf GitHub verfügbar.
Dies wird eine Bootstrap React-Anwendung sein, die wir mit Create React App starten können. Installieren wir das und wechseln dann in den Projektordner.
npx create-react-app unstated-next-form
cd unstated-next-form>
Wir müssen Unstated Next als Abhängigkeit hinzufügen
## yarn
yarn add unstated-next
## npm
npm install --save unstated-next
Wir werden React Hooks und createContainer von Unstated Next verwenden, also importieren wir diese in die App-Komponente
// src/App.js
import React, { useState } from 'react';
import { createContainer } from "unstated-next";
Als Nächstes erstellen wir einen benutzerdefinierten Hook. Dort werden wir unseren Zustand speichern, den wir mit useState erstellen können
// src/App.js
// ...same as before
const useForm = () => {
const [input, setValue] = useState("");
const [name, setName] = useState("Barney Stinson");
const handleInput = event => {
setValue(event.target.value);
};
const updateName = event => {
event.preventDefault();
setName(input);
setValue("");
};
return {
input,
name,
handleInput,
updateName,
};
};
Wir haben hier zwei Zustände definiert. input wird verwendet, um die eingegebenen Werte im Textfeld zu verfolgen und wird mit der Methode handleInput aktualisiert. name wird aktualisiert, wenn der Button geklickt wird, was die Methode updateName auslöst.
OK, jetzt können wir einen Container erstellen, indem wir unseren benutzerdefinierten Hook als Parameter an die Methode createContainer() übergeben.
// src/App.js
// ...same as before
const FormContainer = createContainer(useForm);
Dies erstellt einen Container, den wir in unserer gesamten Anwendung verwenden können. Ja, Sie haben richtig gelesen, aber gehen wir einen Schritt nach dem anderen. Wir beginnen mit dieser einen Komponente, um zu sehen, wie sie mit Unstated Next funktioniert.
Nun erstellen wir eine Form-Komponente, die so aussieht:
// src/App.js
// ...same as before
const Form = () => {
const form = FormContainer.useContainer();
return (
<div>
<p>Hello! {form.name}</p>
<div>
<input
type="text"
value={form.input}
onChange={form.handleInput}
/>
<button onClick={form.updateName}>Save</button>
</div>
</div>
);
};
Wir weisen die Variable form dem Wert zu, der durch Aufrufen von FormContainer.useContainer() erhalten wird. Der Wert enthält die Zustände und Methoden, die im benutzerdefinierten Hook definiert sind, den wir oben erstellt haben. Damit können wir die bereitgestellten Zustände und Methoden nutzen – aber damit dies geschieht, müssen wir die Form-Komponente in einen Provider einpacken.
const App = () => (
<Form.Provider>
<Form />
</Form.Provider>
)
Versuchen Sie mit dem, was Sie bisher gelernt haben, eine minimale To-Do-Anwendung mit Unstated Next zu erstellen. Wenn Sie nicht weiterkommen, können Sie sich gerne dieses Repository ansehen, um zu sehen, wie ich meine erstellt habe.
Beispiel: Zustand über mehrere Komponenten hinweg teilen
OK, Sie haben vorhin einen Hinweis erhalten, dass wir unseren Formular-Container überall verwenden können, wo wir wollen. Einer der Vorteile der Verwendung von Unstated Next ist, dass es möglich ist, den Zustand über mehrere Komponenten hinweg zu teilen. Um zu sehen, wie das funktioniert, werden wir eine kleine App erstellen, die die oben genannten Formularfunktionen verwendet und auch die Erstellung von To-Do-Aufgaben mit demselben Zustand ermöglicht. Der Name des Benutzers kann in der Formular-Komponente aktualisiert werden, und diese Aktualisierung wird auch in der To-Do-Komponente widergespiegelt. Zwei Fliegen mit einer Klappe!

Es gibt auch ein Repo für dieses Beispiel, also klonen oder laden Sie es gerne herunter, während wir voranschreiten.
Lassen Sie uns ein neues Projekt starten und die notwendigen Abhängigkeiten installieren
npx create-react-app unstated-next-app
cd unstated-next-app
yarn unstated-next shortid
Der Zustand für die Anwendung wird in einer separaten Datei leben. Wir möchten die Zustände für die Formular- und To-Do-Komponenten im Store haben und auch die Methoden, die zu ihrer Aktualisierung benötigt werden. Erstellen Sie eine Datei store.js im Verzeichnis src und gestalten Sie sie wie folgt;
// src/store.js
import { useState } from "react";
import shortid from "shortid"
import { createContainer } from 'unstated-next'
export const useStore = () => {
// Construct a list that contains two default tasks
const list = [
{ id: 1, title: 'Write code' },
{ id: 2, title: 'Buy milk' }
]
const [input, setValue] = useState("");
// Let's set a legen -- wait for it -- dary default name that updates on form submit
const [name, setName] = useState("Barney Stinson");
const [todos, addTodo] = useState(list);
const [item, setTodo] = useState("");
const handleInput = event => {
setValue(event.target.value);
};
const updateName = event => {
event.preventDefault();
setName(input);
setValue("");
};
const handleTodo = event => {
setTodo(event.target.value);
};
const handleSubmit = event => {
event.preventDefault();
const value = {
id: shortid.generate(),
title: item
}
addTodo(todos.concat(value));
setTodo("");
};
return {
input,
name,
handleInput,
updateName,
todos,
item,
handleTodo,
handleSubmit
};
}
export const StoreContainer = createContainer(useStore)
Wir verwenden useState(), um die benötigten Zustände zu erstellen. Die Methoden sind definiert und all dies geschieht innerhalb des benutzerdefinierten Hooks useStore(). Wir erstellen den StoreContainer und übergeben dann useStore() als Parameter an createContainer(). Damit können wir den StoreContainer in den notwendigen Komponenten verwenden, wo wir die von uns definierten Zustände und Methoden nutzen möchten.
Beginnen wir mit dem Formularteil. Erstellen Sie eine Datei namens form.js und sie sollte so aussehen, wie ich sie unten habe;
// src/form.js
import React from "react";
import { StoreContainer} from "./store";
const FormComponent = () => {
const form = StoreContainer.useContainer();
return (
<div>
<p>Hello! {form.name}</p>
<div>
<input type="text" value={form.input} onChange={form.handleInput} />
<button onClick={form.updateName}>Change Name</button>
</div>
</div>
);
};
export default FormComponent;
Wir verwenden StoreContainer, um auf die benötigten Zustände und Methoden zuzugreifen. Wir werden dasselbe für die Aufgaben-Komponente tun, die Sie in einer todo.js-Datei erstellen können.
// src/todo.js
import React from "react";
import { StoreContainer } from "./store";
const TodoComponent = () => {
const todo = StoreContainer.useContainer();
return (
<div>
<p>Add Todos</p>
<input type="text" value={todo.item} onChange={todo.handleTodo} />
<button onClick={todo.handleSubmit}>Add</button>
<div>
<p>Dear {todo.name}, here are your current tasks;</p>
{todo.todos.map((item) => {
return (
<ul key={item.id}>
<li>{item.title}</li>
</ul>
);
})}
</div>
</div>
);
};
export default TodoComponent;
Sie sehen, dass todo.name nur in der FormComponent aktualisiert werden kann. Das liegt daran, dass wir eine Möglichkeit benötigen, den Zustand in beiden Komponenten bereitzustellen. Deshalb werden wir uns wieder an Provider wenden und einen in der App-Komponente hinzufügen, so wie wir es im vorherigen Beispiel getan haben.
import React from 'react';
import TodoComponent from "./todo";
import FormComponent from "./form";
import { StoreContainer } from "./store"
function App() {
return (
<div className="App">
<StoreContainer.Provider>
<FormContainer />
<TodoContainer />
</StoreContainer.Provider>
</div>
);
}
export default App;
Da haben wir es! Durch das Hinzufügen des Providers können Daten aus der Formular-Komponente genommen, im Provider gespeichert und wieder an die Aufgabenliste übergeben werden. 💥
Hallo, Jamie Kyle hier
Danke für den Artikel über Unstated Next. Ich schätze es sehr.
Ich möchte jedoch darauf hinweisen, dass ich die Verwendung eines gemeinsamen
StoreContainernicht empfehle. Ich würde empfehlen, einen separatenTodoContainerundFormContainerzu haben. Container sollten eine einzige Verantwortung haben. Wenn Sie versuchen, Redux mit Unstated Next nachzubauen, werden Sie eine schlechte Zeit haben.Ich empfehle auch, nicht für alles Container zu verwenden. Die meisten Zustände können mit einigen benutzerdefinierten Hooks auskommen. Nur wenn Sie wirklich einen gemeinsamen Zustand und eine gemeinsame API haben möchten, sollten Sie zu Containern greifen.
Prost!
Hallo, danke für diesen großartigen Inhalt!
Ich habe festgestellt, dass ich dies ändern musste
<Form.Provider>in dieses
<FormContainer.Provider>damit dieses Beispiel funktioniert.
Beste Grüße
Vielen Dank für diesen Artikel, er ist aktuell und beschäftigt mich definitiv. Da ich Unstated-next nutzen möchte, versuche ich es mit echten Daten abzurufen. Todo-Apps sind großartig, aber wenn es um Zustandsverwaltung geht, sind viele Daten daran beteiligt, und dieses Tutorial behandelt das nicht. Es gibt auch keine Beispiele online, keine. Wenn ich im Zustand von useForms ein Stück Zustand namens names habe, das zunächst ein leeres Array ist, und dann erstelle ich darin eine Funktion namens updateNames, ähnlich wie updateName, und darin verwende ich einen benutzerdefinierten asynchronen useFetch Hook, um "eine Liste aller Namen von einer API abzurufen", um dann das states-Stück names mit diesem Array von Namen zu aktualisieren, z. B. bekomme ich einen direkten Fehler "Ungültiger Hook-Aufruf. Hooks können nur im Körper einer Funktionskomponente aufgerufen werden". Wie kann Unstated-next beim Abrufen und Speichern von Daten verwendet werden, was tatsächlich einer der größten Vorteile eines Stores ist. Ich hoffe, Sie erhalten und beantworten dies schnell! Sie sind so hilfreich und ich wäre Ihnen sehr dankbar. Prost!