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:&nbsp;&nbsp;&nbsp;</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:&nbsp;&nbsp;&nbsp;</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:&nbsp;&nbsp;&nbsp;</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:&nbsp;&nbsp;&nbsp;
            </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:&nbsp;&nbsp;&nbsp;
            </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:&nbsp;&nbsp;&nbsp;
            </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 在您的代码中的工作方式以及通常如何触发重新渲染,几乎没有人误解。

您的代码中发生了什么:

  1. 你用空数组初始化 medicine 状态 属性 -> OK
  2. 您声明了一个新常量 medicineStock,它是 medicine 的过滤版本。此时medicineStock也是一个空数组
  3. 您使用基于 medicineStock 的 initialValue 初始化了 3 个新状态属性。它将产生 3 个新的空字符串。在这里你必须明白,状态的 initialValue 不是设计用来更新它的,而只是用来初始化它的。例如,如果您更新 medicineStock,它不会更新 editMedicineName
  4. 然后你获取一些数据并调用setMedicine来存储它。这将有效触发新的渲染。所以你的函数体将被再次读取。当然 medicineStock 此时会有一个新值,这就是为什么您可以在日志中看到它。但正如我之前所说,这不会更新 editMedicineNameeditMedicineRegNoeditMedicineType。更新这些值的唯一方法是调用它们自己的设置器。

如何解决:

我真的不明白你想在这里实现什么,但对你的代码的简单修复是:

  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());
    })
  },[])