簡體   English   中英

object.key 用於使用 object 作為 map 上的數組,不能將參數作為道具傳遞給 React 組件

[英]object.key for using object as array on map not allwoing to pass argument as props to React component

代碼和框的鏈接- https://codesandbox.io/s/productupload-form-krovj?fontsize=14&hidenavigation=1&theme=dark

在 productupload react 組件中,我使用的是product_specs useState 鈎子,它是數組,但由於其他 useStates 是 object 並且只有 product_specs useState 是數組,因此很難在此實現 handleChange 事件處理程序。 因此,我將 product_specs 更改為 object 而不是數組。 As i cant use map method on object, I have used Object.key but now issue is, I am not able to use argument named as item inside map and pass it to react 零件。 它給出了錯誤,因為無法讀取未定義的屬性長度。 因為我使用 item.specification 作為組件的道具。 有人可以幫助解決這個問題。 注意我不能對組件代碼進行任何更改,因為許多其他組件都依賴於它。

productupload 和 forminput 組件的代碼都在下面給出。

import React, { useState } from "react";
import FormInput from "../Forminput/forminput";
import CustomButton from "../Custombutton/custombutton";
import axios from "axios";

const ProductUpload = () => {
  const [sub_category, setSub_category] = useState("");

  const [product_name, setProduct_name] = useState("");

  const [product_image, setProduct_image] = useState("");

  const [product_specs, setProduct_specs] = useState([
    {
      specification: "",
      specvalue: "",
    },
  ]);
  //note VIMP to add square bracket for array
  const imageSelectedHandler = (event) => {
    setProduct_image({ product_image: event.target.files[0] });
  };

  // const imageUploadHandler = () => {
  //   const fd = new FormData();
  //   fd.append("product_image", product_image, product_image.name); //.name is Imp as name is property of file
  // };

  const handleChange = (e) => {
    const { name, value } = e.target;
    setSub_category({ ...sub_category, [name]: value });
    setProduct_name({ ...product_name, [name]: value });
    setProduct_specs({ ...product_specs, [name]: value });
    // const p_specs = [...product_specs];
    // p_specs[i][name] = value;
    // setProduct_specs(p_specs); //This is 100% right.
    console.log(product_specs);
  };
  //to add extra input field
  const addClick = () => {
    // setProduct_specs([...product_specs, { specification: "", specvalue: "" }]); //this is 100% right
    //also 100% correct alternative to above line
    const p_specs = [...product_specs];
    p_specs.push({ specification: "", specvalue: "" });
    setProduct_specs(p_specs);
  };
  //to remove extra input field
  const removeClick = (i) => {
    const p_specs = [...product_specs];
    p_specs.splice(i, 1);
    setProduct_specs(p_specs);
  };
  const handleSubmit = async (event) => {
    event.preventDefault();
    const newProduct = {
      sub_category,
      product_name,
      product_image,
      product_specs,
    };
    try {
      const config = {
        headers: {
          "Content-Type": "application/json",
        },
      };
      const body = JSON.stringify(newProduct);
      const res = await axios.post("/api/product", body, config);
      console.log(res.data);
    } catch (error) {
      console.error(error.response.data);
    }
  };

  const createUI = () => {
    return Object.keys(product_specs).map((item, i) => {
      return (
        <div key={i} className="inputgroup">
          <FormInput
            type="text"
            name="specification"
            handleChange={(e) => handleChange(e, i)}
            value={item.specification}
            label="specification"
            required
            customwidth="300px"
          ></FormInput>
          <FormInput
            type="text"
            name="specvalue"
            handleChange={(e) => handleChange(e, i)}
            value={item.specvalue}
            label="specification values seperated by quomas"
            required
          ></FormInput>
          <CustomButton
            onClick={() => removeClick(i)}
            type="button"
            value="remove"
            style={{ margin: "12px" }}
          >
            Remove
          </CustomButton>
        </div>
      );
    });
  };
  return (
    <div className="container">
      <form
        action="/upload"
        method="post"
        className="form"
        onSubmit={handleSubmit}
        encType="multipart/form-data"
      >
        <h3 style={{ color: "roboto, sans-serif" }}>
          Add new product to the database
        </h3>
        <div
          style={{
            display: "flex",
            height: "200px",
            width: "200px",
            border: "2px solid #DADCE0",
            borderRadius: "6px",
            position: "relative",
          }}
        >
          <input
            // style={{ display: "none" }}
            type="file"
            accept="image/*"
            onChange={imageSelectedHandler}
            multiple={false}
            name="product_image"
          />
          {/* <CustomButton >
            Select Image
          </CustomButton>
          <CustomButton
          //  onClick={imageUploadHandler}
          >
            Upload
          </CustomButton> */}

          {/*as per brad- type = "submit" value="submit"  this should not be used, file should upload with the form submit */}
          <div>
            <img
              style={{
                width: "100%",
                height: "100%",
              }}
              alt="#"
            />
          </div>
        </div>
        <FormInput
          type="text"
          name="sub_category"
          handleChange={handleChange}
          value={sub_category}
          label="select from subcategories"
          required
        ></FormInput>
        <FormInput
          type="text"
          name="product_name"
          handleChange={handleChange}
          value={product_name}
          label="product name"
          required
        ></FormInput>
        {createUI()}
        <div>
          <CustomButton
            onClick={addClick}
            type="button"
            style={{ margin: "14px" }}
          >
            Add More Fields
          </CustomButton>
          <CustomButton type="submit" style={{ margin: "12px" }}>
            Upload Product
          </CustomButton>
        </div>
      </form>
    </div>
  );
};

export default ProductUpload;

FormInput 組件的代碼

import "./forminput.scss";

const FormInput = ({
  handleChange,
  label,
  customwidth,
  // register, //useForm hook property to handel change automatically
  ...otherProps
}) => (
  <div className="group" style={{ width: customwidth }}>
    <input
      className="form-input"
      onChange={handleChange}
      // ref={register}
      {...otherProps}
    />
    {label ? (
      <label
        className={`${
          otherProps.value.length ? "shrink" : ""
        } form-input-label`}
      >
        {label}
      </label>
    ) : null}
  </div>
);

export default FormInput;

我看到您在 handleChange function 中使用i來了解 product_specs 的索引。 但是對於 product_name 或 product_category 等其他狀態, i的值是未定義的。 所以我認為你可以檢查i是否未定義。

const handleChange = (e, i) => {
    console.log(e.target.value, i);
    const { name, value } = e.target;
    setSub_category({ ...sub_category, [name]: value });
    setProduct_name({ ...product_name, [name]: value });
    const p_specs = [...product_specs];
    if(i) {
        product_specs[i][name] = value;
        setProduct_specs(p_specs); //This is 100% right.
    }
};

而且我認為它不會影響其他組件,因為i只會對 product_specs 有價值。

嘿伙計們這很容易我不需要使用任何 Object.key。 可能有很多選擇,但就我而言,我認為這是最簡單的方法。 在這里分享我的最終代碼。

import FormInput from "../Forminput/forminput";
import CustomButton from "../Custombutton/custombutton";
import axios from "axios";

const ProductUpload = () => {
  const [sub_category, setSub_category] = useState({ sub_category: "" });

  const [product_name, setProduct_name] = useState({ product_name: "" });

  const [product_image, setProduct_image] = useState("");

  const [product_specs, setProduct_specs] = useState([
    {
      specification: "",
      specvalue: "",
    },
  ]);
  //note VIMP to add square bracket for array
  const imageSelectedHandler = (event) => {
    setProduct_image({ product_image: event.target.files[0] });
  };

  // const imageUploadHandler = () => {
  //   const fd = new FormData();
  //   fd.append("product_image", product_image, product_image.name); //.name is Imp as name is property of file
  // };
  const handleChange1 = (e) => {
    const { name, value } = e.target;

    setSub_category({ ...sub_category, [name]: value });
    setProduct_name({ ...product_name, [name]: value });
  };

  const handleChange2 = (e, i) => {
    const { name, value } = e.target;

    const p_specs = [...product_specs];
    p_specs[i][name] = value;
    setProduct_specs(p_specs); //This is 100% right.
  };

  //to add extra input field
  const addClick = () => {
    // setProduct_specs([...product_specs, { specification: "", specvalue: "" }]); //this is 100% right
    //also 100% correct alternative to above line
    const p_specs = [...product_specs];
    p_specs.push({ specification: "", specvalue: "" });
    setProduct_specs(p_specs);
  };
  //to remove extra input field
  const removeClick = (i) => {
    const p_specs = [...product_specs];
    p_specs.splice(i, 1);
    setProduct_specs(p_specs);
  };
  const handleSubmit = async (event) => {
    event.preventDefault();
    const newProduct = {
      sub_category,
      product_name,
      product_image,
      product_specs,
    };
    try {
      const config = {
        headers: {
          "Content-Type": "application/json",
        },
      };
      const body = JSON.stringify(newProduct);
      const res = await axios.post("/api/product", body, config);
      console.log(res.data);
    } catch (error) {
      console.error(error.response.data);
    }
  };

  const createUI = () => {
    return product_specs.map((item, i) => {
      return (
        <div key={i} className="inputgroup">
          <FormInput
            type="text"
            name="specification"
            handleChange={(e) => handleChange2(e, i)}
            value={item.specification}
            label="specification"
            required
            customwidth="300px"
          ></FormInput>
          <FormInput
            type="text"
            name="specvalue"
            handleChange={(e) => handleChange2(e, i)}
            value={item.specvalue}
            label="specification values seperated by quomas"
            required
          ></FormInput>
          <CustomButton
            onClick={() => removeClick(i)}
            type="button"
            value="remove"
            style={{ margin: "12px" }}
          >
            Remove
          </CustomButton>
        </div>
      );
    });
  };
  return (
    <div className="container">
      <form
        action="/upload"
        method="post"
        className="form"
        onSubmit={handleSubmit}
        encType="multipart/form-data"
      >
        <h3 style={{ color: "roboto, sans-serif" }}>
          Add new product to the database
        </h3>
        <div
          style={{
            display: "flex",
            height: "200px",
            width: "200px",
            border: "2px solid #DADCE0",
            borderRadius: "6px",
            position: "relative",
          }}
        >
          <input
            // style={{ display: "none" }}
            type="file"
            accept="image/*"
            onChange={imageSelectedHandler}
            multiple={false}
            name="product_image"
          />
          {/* <CustomButton >
            Select Image
          </CustomButton>
          <CustomButton
          //  onClick={imageUploadHandler}
          >
            Upload
          </CustomButton> */}

          {/*as per brad- type = "submit" value="submit"  this should not be used, file should upload with the form submit */}
          <div>
            <img
              style={{
                width: "100%",
                height: "100%",
              }}
              alt="#"
            />
          </div>
        </div>
        <FormInput
          type="text"
          name="sub_category"
          handleChange={handleChange1}
          value={sub_category.sub_category}
          label="select from subcategories"
          required
        ></FormInput>

        <FormInput
          type="text"
          name="product_name"
          handleChange={handleChange1}
          value={product_name.product_name}
          label="product name"
          required
        ></FormInput>
        {console.log(product_name)}
        {console.log(product_specs)}
        {createUI()}
        <div>
          <CustomButton
            onClick={addClick}
            type="button"
            style={{ margin: "14px" }}
          >
            Add More Fields
          </CustomButton>
          <CustomButton type="submit" style={{ margin: "12px" }}>
            Upload Product
          </CustomButton>
        </div>
      </form>
    </div>
  );
};

export default ProductUpload;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM