Bertindak balas penggerudian sokongan alternatif (terbalikkan, anak kepada ibu bapa) cara untuk memproses borang
P粉419164700
2023-09-01 19:45:14
<p>Saya baru mengenali React dan mempelajarinya melalui beberapa projek praktikal. Saya sedang mengusahakan pemprosesan dan pengesahan borang. Saya menggunakan komponen Borang React Router dalam SPA, dan di dalam borang saya mempunyai elemen FormGroup, yang menjadikan input label dan mesej ralat. Saya juga menggunakan komponen input saya sendiri dalam komponen FormGroup untuk memisahkan logik dan pengurusan keadaan input yang digunakan dalam borang. </p>
<p>Jadi saya meletakkan komponen Borang dan komponen FormGroup dalam contoh halaman log masuk seperti ini: </p>
<p><em>halaman/Log Masuk.js</em></p>
<pre class="brush:js;toolbar:false;">import { useState } daripada 'react';
import { Link, Form, useNavigate, useSubmit } daripada 'react-router-dom';
import FormGroup daripada '../components/UI/FormGroup';
import Butang daripada '../components/UI/Button';
import Kad daripada '../components/UI/Kad';
import './Login.scss';
fungsi LoginPage() {
const navigate = useNavigate();
const submit = useSubmit();
const [isLoginValid, setIsLoginValid] = useState(false);
const [isPasswordValid, setIsPasswordValid] = useState(false);
var resetLoginInput = null;
var resetPasswordInput = null;
biarkan isFormValid = palsu;
if(isLoginValid && isPasswordValid) {
isFormValid = benar;
}
function formSubmitHandler(event) {
event.preventDefault();
if(!isFormValid) {
kembali;
}
resetLoginInput();
resetPasswordInput();
serahkan(event.currentTarget);
}
function loginValidityChangeHandler(isValid) {
setIsLoginValid(isValid);
}
kata laluan fungsiValidityChangeHandler(isValid) {
setIsPasswordValid(isValid);
}
function resetLoginInputHandler(reset) {
resetLoginInput = set semula;
}
function resetPasswordInputHandler(reset) {
resetPasswordInput = set semula;
}
suis fungsiToSignupHandler() {
navigasi('/signup');
}
kembali (
<div className="log masuk">
<div className="log masuk__logo">
Pergi Piala
</div>
<p className="log masuk__description">
Log masuk ke akaun Go Cup anda
</p>
<Sempadan kad>
<Borang onSubmit={formSubmitHandler}>
<FormGroup
id="log masuk"
label="Nama pengguna atau alamat e-mel"
inputProps={{
jenis: "teks",
nama: "log masuk",
kesahan: (nilai) => {
nilai = nilai.trim();
jika(!nilai) {
return [palsu, 'Nama pengguna atau alamat e-mel diperlukan.']
} else if(value.length < 3 || value.length > 30) {
return [false, 'Nama pengguna atau alamat e-mel mesti mempunyai sekurang-kurangnya 3 dan maksimum 30 aksara'];
} lain {
kembali [benar, batal];
}
},
onValidityChange: loginValidityChangeHandler,
onReset: resetLoginInputHandler
}}
/>
<FormGroup
id="kata laluan"
label="Kata Laluan"
sideLabelElement={
<Pautan ke="/kata laluan-reset">
lupa kata laluan?
</Pautan>
}
inputProps={{
jenis: "kata laluan",
nama: "kata laluan",
kesahan: (nilai) => {
nilai = nilai.trim();
jika(!nilai) {
return [palsu, 'Kata laluan diperlukan.']
} else if(value.length < 4 || value.length > 1024) {
return [false, 'Kata laluan mestilah sekurang-kurangnya 4 atau maksimum 1024 aksara panjang.'];
} lain {
kembali [benar, batal];
}
},
onValidityChange: passwordValidityChangeHandler,
onReset: resetPasswordInputHandler
}}/>
<div className="pusat teks">
<Nama kelas butang="w-100" type="serahkan">
Log masuk
</Butang>
<span className="log masuk__atau">
atau
</span>
<Nama kelas butang="w-100" onClick={switchToSignupHandler}>
daftar
</Butang>
</div>
</Borang>
</Kad>
</div>
);
}
eksport Laman Masuk lalai;
</pra>
<p>Seperti yang anda lihat dalam kod di atas, saya menggunakan komponen FormGroup dan menghantar sifat <code>onValidityChange</code> dan <code>onReset</code> / Nilai kod yang dikemas kini> Tukar dan tetapkan semula fungsi untuk menetapkan semula input selepas penyerahan borang, dsb. Gunakan cangkuk tersuai saya useInput untuk mencipta fungsi <code>isValid</code> dan <code>reset</code> Saya menghantar nilai isValid apabila nilai berubah dan menghantar fungsi set semula daripada komponen input menggunakan prop yang ditakrifkan dalam komponen FormGroup. Saya juga menggunakan <code>isLoginValid</code> dan <code>isPasswordValid</code> menyatakan defiend dalam halaman log masuk untuk menyimpan nilai keadaan input <code>isValid</code> komponen. Jadi saya telah menentukan keadaan dalam komponen input dan menyerahkannya kepada komponen induk menggunakan prop dan menyimpan nilainya dalam keadaan lain yang dibuat dalam komponen induk itu. Penggerudian prop yang sedang berlaku membuatkan saya berasa sedikit tidak selesa. </p>
<p>Negeri diuruskan dalam komponen input, saya mempunyai keadaan ini: </p>
<ul>
<li><strong>Nilai: </strong>Masukkan nilai elemen. </li>
<li><strong>isInputTouched</strong>: Menentukan sama ada pengguna telah menyentuh/memfokuskan input untuk menentukan sama ada untuk memaparkan mesej ralat pengesahan, jika ada. </li>
</ul>
<p>Saya menggabungkan dan menggunakan beberapa fungsi (seperti fungsi pengesahan yang dihantar kepada komponen input) kepada kedua-dua keadaan ini untuk mencipta nilai pembolehubah lain untuk mengumpul maklumat tentang input dan kesahihannya, seperti sama ada nilai itu sah (isValid ), sama ada terdapat pengesahan mesej (mesej), jika input adalah sah (<code>isInputValid = isValid || !isInputTouched</code>) untuk memutuskan untuk memaparkan mesej pengesahan.</p>
<p>Keadaan dan nilai ini diuruskan dalam cangkuk tersuai yang saya buat, <code>useInput</code>, seperti ini: </p>
<p><em>hooks/use-state.js</em></p>
<pre class="brush:js;toolbar:false;">import { useState, useCallback } daripada 'react';
fungsi useInput(validityFn) {
const [nilai, setValue] = useState('');
const [isInputTouched, setIsInputTouched] = useState(false);
const [isValid, mesej] = jenis kesahanFn === 'fungsi' ?
const isInputValid = isValid || !isInputTouched;
const inputChangeHandler = useCallback(event => {
setValue(event.target.value);
if(!isInputTouched) {
setIsInputTouched(true);
}
}, [isInputTouched]);
const inputBlurHandler = useCallback(() => {
setIsInputTouched(true);
}, []);
tetapan semula const = useCallback(() => {
setValue('');
setIsInputTouched(false);
}, []);
kembali {
nilai,
ianya sah,
isInputValid,
mesej,
inputChangeHandler,
inputBlurHandler,
set semula
};
}
eksport default useInput;
</pra>
<p>Saya sedang menggunakan cangkuk tersuai ini dalam Input.js seperti ini: </p>
<p><em>komponen/UI/Input.js</em></p>
<pre class="brush:js;toolbar:false;">import { useEffect } daripada 'react';
import useInput daripada '../../hooks/use-input';
import './Input.scss';
fungsi Input(props) {
const {
nilai,
ianya sah,
isInputValid,
mesej,
inputChangeHandler,
inputBlurHandler,
set semula
} = useInput(props.validity);
const {
onIsInputValidOrMessageChange,
onValidityChange,
onReset
} = prop;
biarkan className = 'kawalan borang';
if(!isInputValid) {
className = `${className} form-control--invalid`;
}
if(props.className) {
className = `${className} ${props.className}`;
}
useEffect(() => {
if(onIsInputValidOrMessageChange && typeof onIsInputValidOrMessageChange === 'fungsi') {
onIsInputValidOrMessageChange(isInputValid, mesej);
}
}, [onIsInputValidOrMessageChange, isInputValid, message]);
useEffect(() => {
if(onValidityChange && typeof onValidityChange === 'fungsi') {
onValidityChange(isValid);
}
}, [onValidityChange, isValid]);
useEffect(() => {
if(onReset && typeof onReset === 'fungsi') {
onReset(set semula);
}
}, [onReset, reset]);
kembali (
<masukan
{...props}
className={className}
nilai={nilai}onChange={inputChangeHandler}
onBlur={inputBlurHandler}
/>
);
}
eksport Input lalai;
</pra>
<p>Dalam komponen input, saya terus menggunakan keadaan <code>isInputValid</code> Tetapi saya juga lulus <kod>isInputValid</kod>, <kod>mesej</kod>, <kod>isValid</kod> dan <kod>set semula</kod> untuk digunakan di dalamnya. Untuk melepasi keadaan dan fungsi ini, saya menggunakan <code>onIsInputValidOrMessageChange</code>, <code>onValidityChange</code>, <code>onReset</code> ditakrifkan dalam props anak kepada ibu bapa). </p>
<p>Ini ialah takrifan komponen FormGroup dan cara saya menggunakan keadaan input di dalam FormGroup untuk memaparkan mesej pengesahan (jika ada): </p>
<p><em>components/UI/FormGroup.js</em></p>
<pre class="brush:js;toolbar:false;">import { useState } daripada 'react';
import Input daripada './Input';
import './FormGroup.scss';
function FormGroup(props) {
const [mesej, setMessage] = useState(null);
const [isInputValid, setIsInputValid] = useState(false);
biarkan className = 'form-group';
if(props.className) {
className = `form-group ${props.className}`;
}
biarkan labelCmp = (
<label htmlFor={props.id}>
{props.label}
</label>
);
if(props.sideLabelElement) {
labelCmp = (
<div className="kumpulan-label-bentuk">
{labelCmp}
{props.sideLabelElement}
</div>
);
}
function isInputValidOrMessageChangeHandler(changedIsInputValid, changedMessage) {
setIsInputValid(changedIsInputValid);
setMessage(changedMessage);
}
kembali (
<div className={className}>
{labelCmp}
<Input
id={props.id}
onIsInputValidOrMessageChange={isInputValidOrMessageChangeHandler}
{...props.inputProps}
/>
{!isInputValid && <p>{message}</p>}
</div>
);
}
eksport Kumpulan Borang lalai;
</pra>
<p>Seperti yang anda lihat daripada kod di atas, saya mentakrifkan <kod>mesej</code> dan <kod>isInputValid</code> menyatakan untuk menyimpan <kod>mesej</kod> <kod>isInputValid</kod> Saya telah menentukan 2 keadaan dalam komponen input untuk memegang nilai ini tetapi saya perlu menentukan 2 keadaan lain dalam komponen ini untuk menyimpan nilai yang dikemas kini dan lulus dalam komponen input. Ini agak pelik dan nampaknya bukan cara terbaik untuk melakukannya kepada saya. </p>
<p><strong>Soalannya ialah: </strong>Saya rasa saya boleh menggunakan React Context (useContext) atau React Redux untuk menyelesaikan masalah penggerudian prop di sini. Tetapi saya tidak pasti sama ada pengurusan keadaan semasa saya buruk dan boleh diperbaiki menggunakan React Context atau React Redux. Kerana dari apa yang saya faham, React Context boleh menjadi teruk dalam situasi di mana keadaan sering berubah, tetapi jika Konteks digunakan di seluruh aplikasi, maka ini berfungsi. Di sini saya boleh mencipta konteks untuk menyimpan dan mengemas kini keseluruhan borang, membenarkan pengembangan seluruh bentuk. React Redux, sebaliknya, mungkin tidak sesuai untuk silo, dan mungkin agak berlebihan. Apa pendapat kamu? Apakah alternatif yang lebih baik untuk situasi tertentu ini? </p>
<p><strong>Nota: </strong>Memandangkan saya baru dalam React, saya terbuka kepada semua cadangan anda tentang semua pengekodan saya, daripada kesilapan mudah kepada kesilapan umum. Terima kasih! </p>
Terdapat dua aliran pemikiran utama mengenai pengurusan negeri dalam React: terkawal dan tidak terkawal. Borang terkawal boleh dikawal menggunakan konteks React di mana nilai boleh diakses dari mana-mana sahaja untuk memberikan kereaktifan. Walau bagaimanapun, input terkawal boleh menyebabkan isu prestasi, terutamanya apabila mengemas kini keseluruhan borang pada setiap input. Di sinilah wujudnya borang yang tidak terkawal. Dengan paradigma ini, semua pengurusan negeri mesti memanfaatkan keupayaan asli penyemak imbas untuk memaparkan keadaan. Masalah utama dengan pendekatan ini ialah anda kehilangan aspek React pada borang, anda perlu mengumpul data borang secara manual semasa penyerahan, dan mengekalkan berbilang rujukan untuk ini boleh membosankan.
Input terkawal kelihatan seperti ini:
EDIT: Seperti yang @Arkellys nyatakan, anda tidak semestinya memerlukan rujukan untuk mengumpul data borang, Berikut ialah contoh menggunakan
FormData
dan di luar kawalan:
Sangat jelas daripada kedua-dua contoh bahawa mengekalkan borang berbilang komponen menggunakan mana-mana pendekatan adalah membosankan, jadi perpustakaan sering digunakan untuk membantu anda mengurus borang anda. Saya secara peribadi mengesyorkan React Hook Form sebagai perpustakaan borang yang diuji, diselenggara dengan baik dan mudah digunakan. Ia mengambil bentuk yang tidak terkawal untuk prestasi optimum sambil masih membenarkan anda menonton input tunggal untuk pemaparan reaktif.
Mengenai sama ada anda menggunakan Redux, konteks React atau mana-mana sistem pengurusan keadaan lain, biasanya tiada perbezaan dari segi prestasi, dengan andaian anda melaksanakannya dengan betul. Jika anda menyukai seni bina fluks maka gunakan Redux, tetapi dalam kebanyakan kes konteks React adalah berprestasi dan mencukupi.
Percubaan
useInput
自定义挂钩看起来是解决问题react-hook-form
和react-final-form
anda yang berani tetapi tersasar pada kod >telah diselesaikan. Anda mencipta kerumitan yang tidak perlu dan kesan sampingan yang tidak dapat diramalkan dengan abstraksi ini. Selain itu, anda cermin props a> yang biasanya merupakan anti-corak dalam React.Jika anda benar-benar mahu melaksanakan logik borang anda sendiri (yang saya syorkan untuk tidak lakukan melainkan untuk tujuan pendidikan), anda boleh mengikuti garis panduan ini:
useMemo
和useRef
untuk memaparkan semula sesedikit mungkinIni adalah aspek mudah yang saya gunakan untuk memutuskan antara perpustakaan langgan-terbit seperti Redux dan keadaan penyebaran melalui pepohon komponen.
Jika dua komponen mempunyai hubungan ibu bapa-anak dan paling banyak dua tepi antara satu sama lain, sebarkan keadaan anak kepada ibu bapa
Ibu bapa -> anak1-tahap1 -> anak1-tahap2 ------ OK
Ibu bapa -> anak1-tahap1 ------ OK
Ibu bapa -> anak1-tahap1 -> anak1-tahap2 -> anak1-tahap3 --> Terlalu banyak perjalanan untuk menukar status daripada kanak-kanak1-tahap3 kepada ibu bapa
Sejak pelaksanaan