object.key для использования объекта как массива на карте, не требующего передачи аргумента в качестве реквизита компоненту React - PullRequest
1 голос
/ 01 августа 2020

ссылка для codeandbox- https://codesandbox.io/s/productupload-form-krovj?fontsize=14&hidenavigation=1&theme=dark

В компоненте реакции productupload я использую product_specs useState, и это был массив, но поскольку другие useState являются объектами и только product_specs useState - это массив, было сложно реализовать на нем обработчик события handleChange. Следовательно, я изменил свои product_specs на объект вместо массива. Поскольку я не могу использовать метод карты для объекта, я использовал Object.key , но теперь проблема в том, что я не могу использовать аргумент с именем item внутри карты и передать его для реакции компонент. Он выдает ошибку, поскольку не может прочитать значение свойства undefined. потому что я использую 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;

Ответы [ 2 ]

0 голосов
/ 01 августа 2020

Привет, ребята. Это было очень просто, мне не нужно было использовать 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;
0 голосов
/ 01 августа 2020

Я вижу, вы используете i в функции handleChange, чтобы узнать индекс 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.

...