如何在单击时添加用户输入?

发布于 2025-01-31 00:27:40 字数 6195 浏览 1 评论 0原文

自学成才的编码员。希望我能充分解释这一点。用户通过输入菜肴名称,食物类别,封面IMG等等值来创建食谱烹饪指南。步骤阵列目前只有1个步骤。我想要一个用户可以单击的按钮,将另一个“步骤”和“ gif”添加到步骤数组中。谁能提出一种方法,当用户单击“添加步骤”按钮时,在屏幕上有另一组“步骤”和“ IMG”渲染?我有一个handleaddsteps功能,没有内部。有人推荐使用DOM吗?只想知道这是否是在错误的兔子洞中投入时间之前的好方法。谢谢您的任何建议。


import React from "react";
import { useState, useEffect } from "react";

// Styles
import "./UploadGuide.scss";

// Firebase
import { doc, setDoc } from "firebase/firestore";
import { db, storage } from "../../firebase";
import { v4 as uuidv4 } from "uuid";
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";


function UploadGuide() {
  const [file, setFile] = useState("");
  const [data, setData] = useState({});
  const [percentage, setPercentage] = useState(null);
  // const [stepsCounter, setStepsCounter] = useState(0);

  // Upload IMG
  useEffect(() => {
    const uploadFile = () => {
      
      const name = new Date().getTime() + file.name;
      const storageRef = ref(storage, file.name);
      const uploadTask = uploadBytesResumable(storageRef, file);
      uploadTask.on(
        "state_changed",
        (snapshot) => {
          const progress =
            (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
          console.log("Upload is " + progress + "% done");
          setPercentage(progress);
          switch (snapshot.state) {
            case "paused":
              console.log("Upload is paused");
              break;
            case "running":
              console.log("Upload is running");
              break;
            default:
              break;
          }
        },
        (error) => {
          console.log(error);
        },
        () => {
          // Handle successful uploads on complete
          getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
            setData((prev) => ({ ...prev, img: downloadURL }));
          });
        }
      );
    };
    file && uploadFile();
  }, [file]);

  console.log(file);
  console.log(data);

  // When user clicks Add Steps button, page renders another steps card
  const handleAddSteps = () => {};

  // When user submits guide, upload data to firecloud db and imgs to firebase storage.
  const handleAddGuide = async (e) => {
    e.preventDefault();

    const newId = uuidv4();
    // const stepsArray = []
    await setDoc(doc(db, "guides", newId), {
      author: e.target.author.value,
      categoryId: "100",
      categoryName: e.target.categoryName.value,
      coverGif: data.img,
      id: newId,
      name: e.target.name.value,
      tags: e.target.tags.value,
      // steps: stepsArray
      steps: [
        {
          step: e.target.step.value,
          gif: data.img,
        },
      ],
    });
  };

  return (
    <div className="upload">
      <form onSubmit={handleAddGuide} className="upload__form">
        <div className="upload__card">
          <div className="upload__inputs">
            <label className="upload__label">Guide Name</label>
            <input
              className="upload__input"
              placeholder="Name of your recipe"
              type="name"
              name="name"
              // value=""
            ></input>
          </div>
          <div className="upload__inputs">
            <label className="upload__label">Author</label>
            <input
              className="upload__input"
              type="author"
              name="author"
            ></input>
          </div>
          <div className="upload__inputs">
            <label className="upload__label">Category</label>
            <select
              name="categoryName"
              className="upload__input"
              defaultValue={"Cooking"}
            >
              <option value="Cooking">Cooking</option>
              <option></option>
            </select>
          </div>
          <div className="upload__inputs">
            <label className="upload__label">Tags</label>
            <input
              name="tags"
              className="upload__input upload__input--large"
              placeholder="Add relevant tags to help people find your guide"
            ></input>
          </div>
        </div>

        <div className="upload__card upload__card--addstep">
          <div className="upload__inputs">
            <label className="upload__label">Step 1</label>
            <input
              className="upload__input upload__input--large"
              name="step"
            ></input>
          </div>
          <div className="upload__inputs">
            <div>
              <img src={file ? URL.createObjectURL(file) : ""}></img>
            </div>
            <label
              htmlFor="file"
              style={{ cursor: "pointer" }}
              className="upload__add"
            >
              + IMG
            </label>
            <input
              id="file"
              onChange={(e) => setFile(e.target.files[0])}
              style={{ display: "none" }}
              type="file"
            ></input>
          </div>
        </div>
        <div className="upload__box">
        <button
          className="upload__add"
          onClick={handleAddSteps}
          style={{ cursor: "pointer" }}
        >
          Add Step
        </button>
        </div>
        <div className="upload__cta">
          <button
            disabled={percentage !== null && percentage < 100}
            type="submit"
            className="upload__submit"
            style={{ cursor: "pointer" }}
          >
            Upload
          </button>
        </div>
      </form>
    </div>
  );
}

export default UploadGuide;

这是页面外观的图像: 在此处输入图像描述

如果我缺少任何关键信息,请让我知道。任何建议将不胜感激。谢谢。

Self taught coder. Hopefully I can explain this adequately. Users create recipe cooking guides by inputing values like dish name, food category, cover img, etc. The steps array only has 1 step at the moment. I want a button that users can click that would add another "step" and "gif" to the steps array. Can anyone suggest a method to have another set of "step" and "img" render on screen when the user clicks the Add Step button? I have a handleAddSteps function with nothing inside. Somebody recommended using DOM? Just want to know if this is a good way to go before investing time down the wrong rabbit hole. Thank you kindly for any advice.


import React from "react";
import { useState, useEffect } from "react";

// Styles
import "./UploadGuide.scss";

// Firebase
import { doc, setDoc } from "firebase/firestore";
import { db, storage } from "../../firebase";
import { v4 as uuidv4 } from "uuid";
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";


function UploadGuide() {
  const [file, setFile] = useState("");
  const [data, setData] = useState({});
  const [percentage, setPercentage] = useState(null);
  // const [stepsCounter, setStepsCounter] = useState(0);

  // Upload IMG
  useEffect(() => {
    const uploadFile = () => {
      
      const name = new Date().getTime() + file.name;
      const storageRef = ref(storage, file.name);
      const uploadTask = uploadBytesResumable(storageRef, file);
      uploadTask.on(
        "state_changed",
        (snapshot) => {
          const progress =
            (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
          console.log("Upload is " + progress + "% done");
          setPercentage(progress);
          switch (snapshot.state) {
            case "paused":
              console.log("Upload is paused");
              break;
            case "running":
              console.log("Upload is running");
              break;
            default:
              break;
          }
        },
        (error) => {
          console.log(error);
        },
        () => {
          // Handle successful uploads on complete
          getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
            setData((prev) => ({ ...prev, img: downloadURL }));
          });
        }
      );
    };
    file && uploadFile();
  }, [file]);

  console.log(file);
  console.log(data);

  // When user clicks Add Steps button, page renders another steps card
  const handleAddSteps = () => {};

  // When user submits guide, upload data to firecloud db and imgs to firebase storage.
  const handleAddGuide = async (e) => {
    e.preventDefault();

    const newId = uuidv4();
    // const stepsArray = []
    await setDoc(doc(db, "guides", newId), {
      author: e.target.author.value,
      categoryId: "100",
      categoryName: e.target.categoryName.value,
      coverGif: data.img,
      id: newId,
      name: e.target.name.value,
      tags: e.target.tags.value,
      // steps: stepsArray
      steps: [
        {
          step: e.target.step.value,
          gif: data.img,
        },
      ],
    });
  };

  return (
    <div className="upload">
      <form onSubmit={handleAddGuide} className="upload__form">
        <div className="upload__card">
          <div className="upload__inputs">
            <label className="upload__label">Guide Name</label>
            <input
              className="upload__input"
              placeholder="Name of your recipe"
              type="name"
              name="name"
              // value=""
            ></input>
          </div>
          <div className="upload__inputs">
            <label className="upload__label">Author</label>
            <input
              className="upload__input"
              type="author"
              name="author"
            ></input>
          </div>
          <div className="upload__inputs">
            <label className="upload__label">Category</label>
            <select
              name="categoryName"
              className="upload__input"
              defaultValue={"Cooking"}
            >
              <option value="Cooking">Cooking</option>
              <option></option>
            </select>
          </div>
          <div className="upload__inputs">
            <label className="upload__label">Tags</label>
            <input
              name="tags"
              className="upload__input upload__input--large"
              placeholder="Add relevant tags to help people find your guide"
            ></input>
          </div>
        </div>

        <div className="upload__card upload__card--addstep">
          <div className="upload__inputs">
            <label className="upload__label">Step 1</label>
            <input
              className="upload__input upload__input--large"
              name="step"
            ></input>
          </div>
          <div className="upload__inputs">
            <div>
              <img src={file ? URL.createObjectURL(file) : ""}></img>
            </div>
            <label
              htmlFor="file"
              style={{ cursor: "pointer" }}
              className="upload__add"
            >
              + IMG
            </label>
            <input
              id="file"
              onChange={(e) => setFile(e.target.files[0])}
              style={{ display: "none" }}
              type="file"
            ></input>
          </div>
        </div>
        <div className="upload__box">
        <button
          className="upload__add"
          onClick={handleAddSteps}
          style={{ cursor: "pointer" }}
        >
          Add Step
        </button>
        </div>
        <div className="upload__cta">
          <button
            disabled={percentage !== null && percentage < 100}
            type="submit"
            className="upload__submit"
            style={{ cursor: "pointer" }}
          >
            Upload
          </button>
        </div>
      </form>
    </div>
  );
}

export default UploadGuide;

Here is an image of what the page looks like:
enter image description here

Please let me know if I'm missing any key information. Any advice is appreciated. Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

时光礼记 2025-02-07 00:27:40

由于每个指南都可以有多个步骤,因此我宁愿创建一个处理多个步骤对象数组的状态,而不仅仅是计数器。
这样,您可以在数组中渲染尽可能多的步骤。
然后,添加步骤只是将对象(带有空状态)添加到该数组的问题。

我做了这个功能型的例子,应该足够清楚以表明我的意思:

import React, { useState } from 'react';

const EMPTY_STEP = { text: '', file: null };

export default function App() {
  const [guideSteps, setGuideSteps] = useState([{ ...EMPTY_STEP }]);

  const handleStepChange = (stepIndex, property, value) => {
    setGuideSteps((prevState) => {
      const newGuideSteps = [...prevState];
      newGuideSteps[stepIndex] = { ...newGuideSteps[stepIndex], [property]: value };

      return newGuideSteps;
    });
  };

  const handleAddStep = () => {
    setGuideSteps((prevState) => [...prevState, { ...EMPTY_STEP }]);
  };

  return (
    <div className="Steps">
      {guideSteps.map((step, index) => {
        return (
          <div key={`step-${index + 1}`}>
            <h2>{`Step ${index + 1}`}</h2>
            <input type="text" value={step.text} onChange={(e) => handleStepChange(index, 'text', e.target.files ? e.target.files[0] : null, index)} />
            <input type="file" value={step.file} onChange={(e) => handleStepChange(index, 'file', e.target.value, index)} />
          </div>
        );
      })}
      <button onClick={handleAddStep}>Add Step</button>
    </div>
  );
}

Since each Guide can have multiple steps, I would rather create a state that handles an array of multiple step objects, than just a counter.
With this, you can render as much steps as you have in the array.
Then, adding steps just will be a matter of adding objects (with an empty state) to that array.

I made this functional example, that should be clear enough to show what I mean:

import React, { useState } from 'react';

const EMPTY_STEP = { text: '', file: null };

export default function App() {
  const [guideSteps, setGuideSteps] = useState([{ ...EMPTY_STEP }]);

  const handleStepChange = (stepIndex, property, value) => {
    setGuideSteps((prevState) => {
      const newGuideSteps = [...prevState];
      newGuideSteps[stepIndex] = { ...newGuideSteps[stepIndex], [property]: value };

      return newGuideSteps;
    });
  };

  const handleAddStep = () => {
    setGuideSteps((prevState) => [...prevState, { ...EMPTY_STEP }]);
  };

  return (
    <div className="Steps">
      {guideSteps.map((step, index) => {
        return (
          <div key={`step-${index + 1}`}>
            <h2>{`Step ${index + 1}`}</h2>
            <input type="text" value={step.text} onChange={(e) => handleStepChange(index, 'text', e.target.files ? e.target.files[0] : null, index)} />
            <input type="file" value={step.file} onChange={(e) => handleStepChange(index, 'file', e.target.value, index)} />
          </div>
        );
      })}
      <button onClick={handleAddStep}>Add Step</button>
    </div>
  );
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文