React Native:过滤后的数组无法将值传递给 usestates
React Native: filtered array failed to pass value to usestates
在我的项目中,我在 UseEffect() 中从 firestore 数据库中检索了一个数组列表。之后,我将数组列表过滤成一个名为 medicineStock 的数组,并将每个值传递给新的 React useStates(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,它在 medicine 对象和控制台中包含过滤后的单个数组 return 这个:
[]
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 return 没有值,而第二个 console.log return 我想放入 React usestates 的值。有什么办法可以解决这个问题吗?
我将突出显示与您的代码相关的问题和解决方案:
- 当您尝试初始化输入
useState
时,medicine
数组尚未准备就绪,因为 firestore 调用是异步的,因此当 medicine
数组到达时,输入 useState
(editMedicinName...) 初始值将固定在一个空数组中。
- 你在数据操作中也有一些问题,因为你在你的
editMedicine****
状态中放置了一个 type Array
,但随后在你的输入 onChange
处理程序中你传递了字符串:setEditMedicineName(e.target.value)}
- 第一个问题的解决方案是使用 React hook
useEffects
。
第一个 useEffect
仅在挂载时执行一次,它调用 firestore db,检索药物列表,并将其设置为您的反应状态 medicine
。
当 medicine
更新时,第二个 useEffect
将被触发,您可以在其中更新您的输入基值。
- 第二个问题通过直接将字符串值设置为输入基值来解决。
- 最后但并非最不重要的一点是,我希望你不想展示你的表格,除非你不
接收
medicine
数据,所以放置一个 三进制是个好主意
operator 在 return 之后,所以你可以在加载期间显示一个微调器
操作。
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>
);
}
关于 useState 在您的代码中的工作方式以及通常如何触发重新渲染,几乎没有人误解。
您的代码中发生了什么:
- 你用空数组初始化
medicine
状态 属性 -> OK
- 您声明了一个新常量
medicineStock
,它是 medicine
的过滤版本。此时medicineStock
也是一个空数组
- 您使用基于 medicineStock 的 initialValue 初始化了 3 个新状态属性。它将产生 3 个新的空字符串。在这里你必须明白,状态的 initialValue 不是设计用来更新它的,而只是用来初始化它的。例如,如果您更新 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());
})
},[])
在我的项目中,我在 UseEffect() 中从 firestore 数据库中检索了一个数组列表。之后,我将数组列表过滤成一个名为 medicineStock 的数组,并将每个值传递给新的 React useStates(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,它在 medicine 对象和控制台中包含过滤后的单个数组 return 这个:
[]
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 return 没有值,而第二个 console.log return 我想放入 React usestates 的值。有什么办法可以解决这个问题吗?
我将突出显示与您的代码相关的问题和解决方案:
- 当您尝试初始化输入
useState
时,medicine
数组尚未准备就绪,因为 firestore 调用是异步的,因此当medicine
数组到达时,输入useState
(editMedicinName...) 初始值将固定在一个空数组中。 - 你在数据操作中也有一些问题,因为你在你的
editMedicine****
状态中放置了一个type Array
,但随后在你的输入onChange
处理程序中你传递了字符串:setEditMedicineName(e.target.value)}
- 第一个问题的解决方案是使用 React hook
useEffects
。 第一个useEffect
仅在挂载时执行一次,它调用 firestore db,检索药物列表,并将其设置为您的反应状态medicine
。 当medicine
更新时,第二个useEffect
将被触发,您可以在其中更新您的输入基值。 - 第二个问题通过直接将字符串值设置为输入基值来解决。
- 最后但并非最不重要的一点是,我希望你不想展示你的表格,除非你不
接收
medicine
数据,所以放置一个 三进制是个好主意 operator 在 return 之后,所以你可以在加载期间显示一个微调器 操作。
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>
);
}
关于 useState 在您的代码中的工作方式以及通常如何触发重新渲染,几乎没有人误解。
您的代码中发生了什么:
- 你用空数组初始化
medicine
状态 属性 -> OK - 您声明了一个新常量
medicineStock
,它是medicine
的过滤版本。此时medicineStock
也是一个空数组 - 您使用基于 medicineStock 的 initialValue 初始化了 3 个新状态属性。它将产生 3 个新的空字符串。在这里你必须明白,状态的 initialValue 不是设计用来更新它的,而只是用来初始化它的。例如,如果您更新 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());
})
},[])