Reagieren Sie auf alternative Unterstützungsbohrungen (umgekehrt, untergeordnetes Element zu übergeordnetem Element), um Formulare zu verarbeiten
<p>Ich bin React-Neuling und lerne es durch einige praktische Projekte. Ich arbeite derzeit an der Formularverarbeitung und -validierung. Ich verwende die Form-Komponente von React Router in einem SPA und im Formular befindet sich ein FormGroup-Element, das Beschriftungseingaben und Fehlermeldungen rendert. Ich verwende auch meine eigene Eingabekomponente innerhalb der FormGroup-Komponente, um die Logik- und Statusverwaltung der im Formular verwendeten Eingaben zu trennen. </p>
<p>Also habe ich die Form-Komponente und die FormGroup-Komponente wie folgt auf der Beispiel-Anmeldeseite platziert: </p>
<p><em>pages/Login.js</em></p>
<pre class="brush:js;toolbar:false;">import { useState } from 'react';
import { Link, Form, useNavigate, useSubmit } from 'react-router-dom';
FormGroup aus '../components/UI/FormGroup' importieren;
Button aus '../components/UI/Button' importieren;
Karte aus '../components/UI/Card' importieren;
import './Login.scss';
Funktion LoginPage() {
const navigation = useNavigate();
constsubmit = useSubmit();
const [isLoginValid, setIsLoginValid] = useState(false);
const [isPasswordValid, setIsPasswordValid] = useState(false);
var resetLoginInput = null;
var resetPasswordInput = null;
let isFormValid = false;
if(isLoginValid && isPasswordValid) {
isFormValid = true;
}
Funktion formSubmitHandler(event) {
event.preventDefault();
if(!isFormValid) {
zurückkehren;
}
resetLoginInput();
resetPasswordInput();
einreichen(event.currentTarget);
}
Funktion loginValidityChangeHandler(isValid) {
setIsLoginValid(isValid);
}
Funktion passwortValidityChangeHandler(isValid) {
setIsPasswordValid(isValid);
}
Funktion resetLoginInputHandler(reset) {
resetLoginInput = zurücksetzen;
}
Funktion resetPasswordInputHandler(reset) {
resetPasswordInput = zurücksetzen;
}
Funktion switchToSignupHandler() {
navigieren('/signup');
}
zurückkehren (
<div className="login">
<div className="login__logo">
Go Cup
</div>
<p className="login__description">
Melden Sie sich bei Ihrem Go Cup-Konto an
</p>
<Kartenrand>
<Form onSubmit={formSubmitHandler}>
<FormGroup
id="Anmelden"
label="Benutzername oder E-Mail-Adresse"
inputProps={{
Typ: "Text",
Name: "Anmelden",
Gültigkeit: (Wert) => {
value = value.trim();
if(!value) {
return [false, 'Benutzername oder E-Mail-Adresse ist erforderlich.']
} else if(value.length < 3 || value.length > 30) {
return [false, 'Benutzername oder E-Mail-Adresse müssen mindestens 3 und maximal 30 Zeichen haben'];
} anders {
return [true, null];
}
},
onValidityChange: loginValidityChangeHandler,
onReset: resetLoginInputHandler
}}
/>
<FormGroup
id="Passwort"
label="Passwort"
sideLabelElement={
<Link zu="/password-reset">
Passwort vergessen?
</Link>
}
inputProps={{
Typ: "Passwort",
Name: "Passwort",
Gültigkeit: (Wert) => {
value = value.trim();
if(!value) {
return [false, „Passwort ist erforderlich.“]
} else if(value.length < 4 || value.length > 1024) {
return [false, 'Passwort muss mindestens 4 oder maximal 1024 Zeichen lang sein.'];
} anders {
return [true, null];
}
},
onValidityChange: passwortValidityChangeHandler,
onReset: resetPasswordInputHandler
}}/>
<div className="text-center">
<Button className="w-100" type="submit">
Anmeldung
</Button>
<span className="login__or">
oder
</span>
<Button className="w-100" onClick={switchToSignupHandler}>
Melden Sie sich an
</Button>
</div>
</Formular>
</Karte>
</div>
);
}
Standard-LoginPage exportieren;
</pre>
<p>Wie Sie im obigen Code sehen können, verwende ich die FormGroup-Komponente und übergebe die Eigenschaften <code>onValidityChange</code>, um <code>isValid< / Der aktualisierte Wert des Codes> Änderungen und Rücksetzfunktionen zum Zurücksetzen der Eingaben nach dem Absenden des Formulars usw. Verwenden Sie meinen benutzerdefinierten Hook useInput, um die Funktionen <code>isValid</code> und <code>reset</code> zu erstellen. Ich übergebe den isValid-Wert, wenn sich der Wert ändert, und übergebe die Reset-Funktion von der Eingabekomponente mithilfe von Requisiten, die in der FormGroup-Komponente definiert sind. Ich verwende auch die Statuswerte <code>isLoginValid</code> auf der Anmeldeseite, um den aktualisierten Statuswert <code>isValid</code> zu speichern Komponente. Also habe ich Zustände in der Eingabekomponente definiert und sie mithilfe von Requisiten an die übergeordnete Komponente übergeben und ihre Werte in anderen Zuständen gespeichert, die in dieser übergeordneten Komponente erstellt wurden. Die Propellerbohrungen, die gerade stattfanden, bereiteten mir ein wenig Unbehagen. </p>
<p>Der Status wird innerhalb der Eingabekomponente verwaltet. Ich habe diese Status: </p>
<ul>
<li><strong>Wert: </strong>Geben Sie den Wert des Elements ein. </li>
<li><strong>isInputTouched</strong>: Bestimmt, ob der Benutzer die Eingabe berührt/fokussiert hat, um zu bestimmen, ob gegebenenfalls eine Validierungsfehlermeldung angezeigt werden soll. </li>
</ul>
<p>Ich kombiniere und wende einige Funktionen (z. B. die an die Eingabekomponente übergebene Validierungsfunktion) auf diese beiden Zustände an, um andere Variablenwerte zu erstellen und Informationen über die Eingabe und ihre Gültigkeit zu sammeln, z. B. ob der Wert gültig ist (isValid), ob eine Nachrichtenüberprüfung vorliegt (Nachricht), ob die Eingabe gültig ist (<code>isInputValid = isValid || !isInputTouched</code>), um zu entscheiden, ob die Überprüfungsnachricht angezeigt werden soll.</p>
<p>Diese Zustände und Werte werden in einem benutzerdefinierten Hook verwaltet, den ich erstellt habe, <code>useInput</code>, wie folgt: </p>
<p><em>hooks/use-state.js</em></p>
<pre class="brush:js;toolbar:false;">import { useState, useCallback } from 'react';
Funktion useInput(validityFn) {
const [value, setValue] = useState('');
const [isInputTouched, setIsInputTouched] = useState(false);
const [isValid, message] = typeof validityFn === 'function' ? validityFn(value) : [true, null];
const isInputValid = isValid ||.
const inputChangeHandler = useCallback(event => {
setValue(event.target.value);
if(!isInputTouched) {
setIsInputTouched(true);
}
}, [isInputTouched]);
const inputBlurHandler = useCallback(() => {
setIsInputTouched(true);
}, []);
const reset = useCallback(() => {
setValue('');
setIsInputTouched(false);
}, []);
zurückkehren {
Wert,
ist gültig,
isInputValid,
Nachricht,
inputChangeHandler,
inputBlurHandler,
zurücksetzen
};
}
Standardwert exportieren useInput;
</pre>
<p>Ich verwende derzeit diesen benutzerdefinierten Hook in Input.js wie folgt: </p>
<p><em>components/UI/Input.js</em></p>
<pre class="brush:js;toolbar:false;">import { useEffect } from 'react';
importiere useInput aus '../../hooks/use-input';
import './Input.scss';
Funktion Input(props) {
const {
Wert,
ist gültig,
isInputValid,
Nachricht,
inputChangeHandler,
inputBlurHandler,
zurücksetzen
} = useInput(props.validity);
const {
onIsInputValidOrMessageChange,
onValidityChange,
onReset
} = Requisiten;
let className = 'form-control';
if(!isInputValid) {
className = `${className} form-control--invalid`;
}
if(props.className) {
className = `${className} ${props.className}`;
}
useEffect(() => {
if(onIsInputValidOrMessageChange && typeof onIsInputValidOrMessageChange === 'function') {
onIsInputValidOrMessageChange(isInputValid, message);
}
}, [onIsInputValidOrMessageChange, isInputValid, message]);
useEffect(() => {
if(onValidityChange && typeof onValidityChange === 'function') {
onValidityChange(isValid);
}
}, [onValidityChange, isValid]);
useEffect(() => {
if(onReset && typeof onReset === 'function') {
onReset(reset);
}
}, [onReset, zurücksetzen]);
zurückkehren (
<Eingabe
{...Requisiten}
className={className}
Wert={Wert}onChange={inputChangeHandler}
onBlur={inputBlurHandler}
/>
);
}
Standardeingabe exportieren;
</pre>
<p>In der Eingabekomponente verwende ich direkt den Status <code>isInputValid</code>, um die ungültige CSS-Klasse zur Eingabe hinzuzufügen. Ich übergebe aber auch die Funktionen <code>isInputValid</code>, <code>message</code> und <code>reset</code> an die übergeordnete Komponente darin zu verwenden. Um diese Zustände und Funktionen zu übergeben, verwende ich die in props definierten Funktionen <code>onIsInputValidOrMessageChange</code>, <code>onValidityChange</code> (Props-Drilldown, aber Richtung). Kind zu Eltern). </p>
<p>Dies ist die Definition der FormGroup-Komponente und wie ich den Eingabestatus innerhalb der FormGroup verwende, um die Validierungsmeldung (falls vorhanden) anzuzeigen: </p>
<p><em>components/UI/FormGroup.js</em></p>
<pre class="brush:js;toolbar:false;">import { useState } from 'react';
Eingabe aus './Input' importieren;
import './FormGroup.scss';
Funktion FormGroup(props) {
const [message, setMessage] = useState(null);
const [isInputValid, setIsInputValid] = useState(false);
let className = 'form-group';
if(props.className) {
className = `form-group ${props.className}`;
}
let labelCmp = (
<label htmlFor={props.id}>
{props.label}
</label>
);
if(props.sideLabelElement) {
labelCmp = (
<div className="form-label-group">
{labelCmp}
{props.sideLabelElement}
</div>
);
}
Funktion isInputValidOrMessageChangeHandler(changedIsInputValid, changesMessage) {
setIsInputValid(changedIsInputValid);
setMessage(changedMessage);
}
zurückkehren (
<div className={className}>
{labelCmp}
<Eingabe
id={props.id}
onIsInputValidOrMessageChange={isInputValidOrMessageChangeHandler}
{...props.inputProps}
/>
{!isInputValid && <p>{message}</p>}
</div>
);
}
Standard-FormGroup exportieren;
</pre>
<p>Wie Sie dem obigen Code entnehmen können, habe ich die Zustände <code>message</code> definiert, um die aktualisierte <code>message</code> zu speichern <code>isInputValid</code> code> Der von der Eingabekomponente übergebene Status. Ich habe in der Eingabekomponente zwei Zustände definiert, um diese Werte zu speichern, aber ich muss in dieser Komponente zwei weitere Zustände definieren, um die aktualisierten und übergebenen Werte in der Eingabekomponente zu speichern. Das ist etwas seltsam und scheint mir nicht die beste Art zu sein, es zu tun. </p>
<p><strong>Die Frage ist: </strong>Ich denke, ich kann React Context (useContext) oder React Redux verwenden, um das Propellerbohrproblem hier zu lösen. Ich bin mir jedoch nicht sicher, ob meine aktuelle Statusverwaltung schlecht ist und mithilfe von React Context oder React Redux verbessert werden kann. Denn soweit ich weiß, kann React Context in Situationen, in denen sich der Status häufig ändert, schrecklich sein, aber wenn der Kontext anwendungsweit verwendet wird, funktioniert dies. Hier kann ich einen Kontext erstellen, um das gesamte Formular zu speichern und zu aktualisieren und so eine formularweite Erweiterung zu ermöglichen. React Redux hingegen passt möglicherweise nicht am besten zum Silo und ist möglicherweise etwas übertrieben. Was denken Sie? Was könnte in dieser besonderen Situation eine bessere Alternative sein? </p>
<p><strong>Hinweis: </strong>Da ich neu bei React bin, bin ich offen für alle Ihre Vorschläge zu meiner gesamten Codierung, von einfachen Fehlern bis hin zu allgemeinen Fehlern. Danke! </p>