В моем проекте я получил список массивов из базы данных firestore в UseEffect(). После этого я отфильтровал список массивов в один массив с именем MedicineStock и передал каждое значение в новые состояния использования React (editMedicineName, editMedicineRegNo и editMedicineType) и сделал их значениями в моем вводе, однако он ничего не передает в каждый useStates, и мое поле ввода остается пустым.
function EditMedicine() {
const { medicineId } = useParams();
const [medicine, setMedicine] = useState([]);
useEffect(() => {
const q = query(collection(db, 'medicine'), where("isAccepted", "==", true) )
onSnapshot(q, (querySnapshot) => {
setMedicine(querySnapshot.docs.map(doc => ({
id: doc.id,
data: doc.data()
})))
})
},[])
const medicineStock = medicine.filter(medicineStock => medicineStock.id === medicineId);
const [editMedicineName, setEditMedicineName] = useState(medicineStock.map(item => item.data.medicineName).toString());
const [editMedicineRegNo, setEditMedicineRegNo] = useState(medicineStock.map(item => item.data.medicineRegNo).toString());
const [editMedicineType, setEditMedicineType] = useState(medicineStock.map(item => item.data.medicineType).toString());
return (
<div className='editMedicine'>
<div className="editMedicine-title">Edit Medicine</div>
<form className="editMedicine-form" >
<div>
<p>
<label className="editMedicine-dataTitle">Name: </label>
<input
name="medicineName"
type="text"
required
className="editMedicine-input"
value={editMedicineName}
onChange={(e) => setEditMedicineName(e.target.value)}
/>
</p>
<p>
<label className="editMedicine-dataTitle">Reg No: </label>
<input
name="medicineRegNo"
type="text"
required
className="editMedicine-input"
value={editMedicineRegNo}
onChange={(e) => setEditMedicineRegNo(e.target.value)}
/>
</p>
<p>
<label className="editMedicine-dataTitle">Type: </label>
<select className="editMedicine-input" value={editMedicineType} onChange={(e) => setEditMedicineType(e.target.value)}>
<option value="Tablet">Tablet</option>
<option value="Capsule">Capsule</option>
<option value="Liquid">Liquid</option>
<option value="Spray">Spray</option>
<option value="Cream">Cream</option>
<option value="Ointment">Ointment</option>
</select>
</p>
</div>
</form>
</div>
)
}
Я устал в console.log для MedicineStock, который содержит отфильтрованный одиночный массив в объекте медицины, и консоль возвращает это:
[]
length: 0
[[Prototype]]: Array(0)
[{…}]
0:
data:
donationId: "XOCXD3FFaWGjO3oZcJmc"
medicineName: "Fluticasone Nasal Spray BP 50 mcg"
medicineRegNo: "MAL14125126AZ"
medicineType: "Spray"
[[Prototype]]: Object
id: "Ko6KqA9nyIotUVOkmfPL"
[[Prototype]]: Object
length: 1
[[Prototype]]: Array(0)
Где первый console.log не возвращает значения, а второй console.log возвращает значение, которое я хочу поместить в состояния использования React. Есть ли какое-нибудь решение для решения этой проблемы?
Я выделю проблемы и решения, связанные с вашим кодом:
useState
, массив medicine
еще не готов, поскольку вызов firestore является асинхронным, поэтому, когда поступает массив medicine
, начальные значения входов useState
(editMedicinName...) будут привязаны к пустому массиву.type Array
внутри своих editMedicine****
состояний, но затем в обработчиках ввода onChange
вы передаете строки: setEditMedicineName(e.target.value)}
useEffects
.
Первый useEffect
выполняется только один раз при монтировании, он вызывает пожарная база данных, извлекает список лекарств и устанавливает его в состояние вашей реакции medicine
.
Когда medicine
обновляется, срабатывает второй useEffect
, и внутри него вы можете обновить свои входные базовые значения.medicine
данные, поэтому рекомендуется поместить троичный
оператор после возврата, чтобы вы могли показывать счетчик во время загрузки
операции.function EditMedicine() {
const { medicineId } = useParams();
const [medicine, setMedicine] = useState([]);
useEffect(() => {
const q = query(
collection(db, 'medicine'),
where('isAccepted', '==', true)
);
onSnapshot(q, (querySnapshot) => {
// setMedicine is called asynchronously
setMedicine(
querySnapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
}))
);
});
}, []);
// Filter medicine array, when it will be retrieved from firestore
const medicineStock = useMemo(
() =>
medicine.filter((medicineStock) => medicineStock.id === medicineId)[0]
.data,
[medicine]
);
const [editMedicineName, setEditMedicineName] = useState(null);
const [editMedicineRegNo, setEditMedicineRegNo] = useState(null);
const [editMedicineType, setEditMedicineType] = useState(null);
/* Set editMedicineName, editMedicineRegNo and editMedicineType when medicine array is retrieved */
useEffect(() => {
if (medicine) {
setEditMedicineName(medicineStock.medicineName);
setEditMedicineRegNo(medicineStock.medicineRegNo);
setEditMedicineType(medicineStock.medicinType);
}
}, [medicine]);
return !medicine ? "Loading..." :(
<div className="editMedicine">
<div className="editMedicine-title">Edit Medicine</div>
<form className="editMedicine-form">
<div>
<p>
<label className="editMedicine-dataTitle">
Name:
</label>
<input
name="medicineName"
type="text"
required
className="editMedicine-input"
value={editMedicineName}
onChange={(e) => setEditMedicineName(e.target.value)}
/>
</p>
<p>
<label className="editMedicine-dataTitle">
Reg No:
</label>
<input
name="medicineRegNo"
type="text"
required
className="editMedicine-input"
value={editMedicineRegNo}
onChange={(e) => setEditMedicineRegNo(e.target.value)}
/>
</p>
<p>
<label className="editMedicine-dataTitle">
Type:
</label>
<select
className="editMedicine-input"
value={editMedicineType}
onChange={(e) => setEditMedicineType(e.target.value)}
>
<option value="Tablet">Tablet</option>
<option value="Capsule">Capsule</option>
<option value="Liquid">Liquid</option>
<option value="Spray">Spray</option>
<option value="Cream">Cream</option>
<option value="Ointment">Ointment</option>
</select>
</p>
</div>
</form>
</div>
);
}
Привет, вот обновление: я все еще не могу заставить его работать, второй useEffect, где установка editMedicine****
будет иметь проблемы с чтением medicineStock
, поскольку терминал возвращает В React Hook useEffect отсутствуют зависимости: «medicineStock.medicineName», «medicineStock.medicineRegNo», «medicineStock.medicineType». Либо включите их, либо удалите массив зависимостей. Можете ли вы помочь мне в этом вопросе?
Если вы жалуетесь, что вы не установили все зависимости. Это будет работать даже без них, так как medicine
dep будет гидратировать MedicineStock in useMemo, но если вы не хотите подавлять lint warn, поместите эти значения в массив deps. Вы также можете заменить medicine
на medicineStock
во втором полезном эффекте.
Существует несколько неправильных представлений о том, как useState работает в вашем коде и вообще о том, как вы можете инициировать повторную визуализацию.
Что происходит в вашем коде:
medicine
пустым массивом -> OKmedicineStock
, которая является отфильтрованной версией medicine
. На данный момент medicineStock
тоже пустой массив.editMedicineName
.setMedicine
для их сохранения. Это приведет к запуску нового рендеринга. Таким образом, тело вашей функции будет прочитано снова. Конечно, в этот момент medicineStock
будет иметь новое значение, поэтому вы можете увидеть это в своем журнале. Но, как я уже говорил, это не обновит editMedicineName
, editMedicineRegNo
и editMedicineType
. Единственный способ обновить эти значения — вызвать их собственные сеттеры.Как это исправить:
Я действительно не понимаю, чего вы пытаетесь достичь здесь, но простым исправлением для вашего кода будет:
const [editMedicineName, setEditMedicineName] = useState();
const [editMedicineRegNo, setEditMedicineRegNo] = useState();
const [editMedicineType, setEditMedicineType] = useState();
useEffect(() => {
const q = query(collection(db, 'medicine'), where("isAccepted", "==", true) )
onSnapshot(q, (querySnapshot) => {
const medecine = querySnapshot.docs.map(doc => ({
id: doc.id,
data: doc.data()
}));
const medicineStock = medicine.filter(medicineStock => medicineStock.id === medicineId);
setEditMedicineName(medicineStock.map(item => item.data.medicineName).toString());
setEditMedicineRegNo(medicineStock.map(item => item.data.medicineRegNo).toString());
setEditMedicineType(medicineStock.map(item => item.data.medicineType).toString());
})
},[])
Спасибо! Я решил свою ошибку на вашем примере, и данные о запасах лекарств успешно перешли в состояния использования React.
Спасибо за подробное объяснение! Я постараюсь реализовать ваши решения и сообщить, решена ли проблема через несколько часов, так как здесь уже полночь.