英文:
Complex Select and Input Text Filed Combo with add more and remove option
问题
我有一个下拉框,还有一个文本字段。用户可以选择他们提供的链接类型,然后在输入文本中提供链接。此外,他们可以添加不同类型的更多链接。每种类型只能有一个链接。如果他们犯了错误,他们可以移除任何链接。
我陷入了这个问题,无法找到任何简单的解决方案。
所需的最终输出是一个数组 projectLinks。[{web:"url"},{android:"url"}]
请帮忙。
import { useState } from "react";
import MainLayout from "./layouts/MainLayout";
const linkOptions = [
  { value: "web", label: "Web" },
  { value: "android", label: "Android" },
  { value: "ios", label: "iOS" },
  { value: "youtube", label: "Youtube" },
  { value: "twitter", label: "Twitter" }
];
type ProjectLinks = [
  { web?: string },
  { android?: string },
  { ios?: string },
  { youtube?: string },
  { twitter?: string }
];
export default function App() {
  const [projectLinks, setProjectLinks] = useState<ProjectLinks>();
  const [numberOfLinks, setNumberOfLinks] = useState(1);
  const handleChangeOption = (event: any) => {
    console.log(event.target.value);
  };
  const submit = () => {
    console.log("已提交");
  };
  const handleAddLink = () => {
    setNumberOfLinks((prev) => prev + 1);
  };
  const handleRemoveLink = () => {
    setNumberOfLinks((prev) => prev - 1);
  };
  return (
    <MainLayout>
      <div className="flex flex-col">
        {[...Array(numberOfLinks)].map((_, index) => (
          <LinkField
            key={index}
            handleChangeOption={handleChangeOption}
            handleAddLink={handleAddLink}
            handleRemoveLink={handleRemoveLink}
          />
        ))}
        <button className="btn btn-active mt-8" onClick={submit}>
          按钮
        </button>
      </div>
    </MainLayout>
  );
}
function LinkField({
  handleChangeOption,
  handleAddLink,
  handleRemoveLink
}: {
  handleChangeOption: (event: any) => void;
  handleAddLink: () => void;
  handleRemoveLink: () => void;
}) {
  return (
    <div className="mt-1 mb-1">
      <div className="flex justify-between">
        <select onChange={handleChangeOption} className="select select-primary">
          {linkOptions.map((option, index) => (
            <option key={index} value={option.value}>
              {option.label}
            </option>
          ))}
        </select>
        <input
          type="text"
          placeholder="example.com"
          className="input input-bordered ml-1 mr-1"
        />
        <button
          className="btn btn-md btn-active ml-1 mr-1"
          onClick={handleAddLink}
        >
          添加
        </button>
        <button
          className="btn btn-md btn-active ml-1 mr-1"
          onClick={handleRemoveLink}
        >
          移除
        </button>
      </div>
    </div>
  );
}
我正在使用 tailwindcss 和 daisyui。
英文:
I have a drop down also a text filed. User can select which kind of link they are providing and then give link in input text.
Also they can add more links of different kind. Only 1 link of 1 kind.
If they made mistake they can remove any link.
I am stuck in this problem and unable to figure out any simple solution.
Final output required is an array projectLinks. [{web:"url"},{android:"url"}]
Please help.
import MainLayout from "./layouts/MainLayout";
const linkOptions = [
{ value: "web", label: "Web" },
{ value: "android", label: "Android" },
{ value: "ios", label: "iOS" },
{ value: "youtube", label: "Youtube" },
{ value: "twitter", label: "Twitter" }
];
type ProjectLinks = [
{ web?: string },
{ android?: string },
{ ios?: string },
{ youtube?: string },
{ twitter?: string }
];
export default function App() {
const [projectLinks, setProjectLinks] = useState<ProjectLinks>();
const [numberOfLinks, setNumberOfLinks] = useState(1);
const handleChangeOption = (event: any) => {
console.log(event.target.value);
};
const submit = () => {
console.log("Submitted");
};
const handleAddLink = () => {
setNumberOfLinks((prev) => prev + 1);
};
const handleRemoveLink = () => {
setNumberOfLinks((prev) => prev - 1);
};
return (
<MainLayout>
<div className="flex flex-col">
{[...Array(numberOfLinks)].map((_, index) => (
<LinkField
key={index}
handleChangeOption={handleChangeOption}
handleAddLink={handleAddLink}
handleRemoveLink={handleRemoveLink}
/>
))}
<button className="btn btn-active mt-8" onClick={submit}>
Button
</button>
</div>
</MainLayout>
);
}
function LinkField({
handleChangeOption,
handleAddLink,
handleRemoveLink
}: {
handleChangeOption: (event: any) => void;
handleAddLink: () => void;
handleRemoveLink: () => void;
}) {
return (
<div className="mt-1 mb-1">
<div className="flex justify-between">
<select onChange={handleChangeOption} className="select select-primary">
{linkOptions.map((option, index) => (
<option key={index} value={option.value}>
{option.label}
</option>
))}
</select>
<input
type="text"
placeholder="example.com"
className="input input-bordered ml-1 mr-1"
/>
<button
className="btn btn-md btn-active ml-1 mr-1"
onClick={handleAddLink}
>
Add
</button>
<button
className="btn btn-md btn-active ml-1 mr-1"
onClick={handleRemoveLink}
>
Remove
</button>
</div>
</div>
);
}
I am using tailwindcss with daisyui.
答案1
得分: 1
我通过避免大部分状态变量并使用表单提交来解决了这个问题。
import { useState } from "react";
import MainLayout from "./layouts/MainLayout";
const linkOptions = [
  { value: "web", label: "Web" },
  { value: "android", label: "Android" },
  { value: "ios", label: "iOS" },
  { value: "youtube", label: "Youtube" },
  { value: "twitter", label: "Twitter" }
];
type ProjectLinks = [
  { web?: string },
  { android?: string },
  { ios?: string },
  { youtube?: string },
  { twitter?: string }
];
export default function App() {
  const [count, setCount] = useState(1);
  const [urlError, setUrlError] = useState(false);
  const submit = (event: any) => {
    let urlTypeArray: string[] = [];
    let urlArray: string[] = [];
    let projectLinks: ProjectLinks[] = [];
    [...Array(count)].map((_, index) => {
      let url =
        count === 1 ? event.target.url.value : event.target.url[index].value;
      let urlType =
        count === 1
          ? event.target.urlType.value
          : event.target.urlType[index].value;
      if (
        urlTypeArray.includes(urlType) ||
        urlArray.includes(url) ||
        !url.length
      ) {
        setUrlError(true);
        return null;
      } else {
        urlTypeArray.push(urlType);
        urlArray.push(url);
        var urlObj: any = {};
        urlObj[urlType] = url;
        projectLinks = [...projectLinks, urlObj];
      }
    });
    if (!urlError && projectLinks.length) {
      console.log(projectLinks);
      // 提交到API的URL操作
    }
    event.preventDefault();
  };
  const handleAddLink = () => {
    setCount((prev) => (prev < linkOptions.length ? prev + 1 : prev));
  };
  const handleRemoveLink = () => {
    setCount((prev) => (prev > 1 ? prev - 1 : prev));
  };
  return (
    <MainLayout>
      <form className="flex flex-col" onSubmit={submit}>
        {[...Array(count)].map((link, index) => (
          <LinkField
            key={index}
            index={index}
            handleAddLink={handleAddLink}
            handleRemoveLink={handleRemoveLink}
          />
        ))}
        <button
          className={`btn ${urlError ? "btn-disabled" : "btn-active"} mt-8`}
        >
          Button
        </button>
        {urlError ? (
          <div
            className="toast cursor-pointer"
            onClick={() => setUrlError(false)}
          >
            <div className="alert alert-error">
              <span>Duplicate URL Type or URL or URL is Empty.</span>
            </div>
          </div>
        ) : null}
      </form>
    </MainLayout>
  );
}
function LinkField({
  handleAddLink,
  handleRemoveLink,
  index
}: {
  handleAddLink: () => void;
  handleRemoveLink: () => void;
  index: number;
}) {
  return (
    <div className="mt-1 mb-1">
      <div className="flex justify-between">
        <select name="urlType" className="select select-primary">
          {linkOptions.map((option, index) => (
            <option key={index} value={option.value}>
              {option.label}
            </option>
          ))}
        </select>
        <input
          type="text"
          name="url"
          placeholder="example.com"
          className="input input-bordered ml-1 mr-1"
        />
        <button
          className={`btn ${
            index === linkOptions.length - 1 ? "btn-disabled" : ""
          } ml-1 mr-1`}
          onClick={handleAddLink}
          type="button"
        >
          Add
        </button>
        <button
          className={`btn ${index === 0 ? "btn-disabled" : ""} ml-1 mr-1`}
          onClick={handleRemoveLink}
          // type="button"
        >
          Remove
        </button>
      </div>
    </div>
  );
}
英文:
I solved it by avoiding most of the state variables and used form submit.
import { useState } from "react";
import MainLayout from "./layouts/MainLayout";
const linkOptions = [
{ value: "web", label: "Web" },
{ value: "android", label: "Android" },
{ value: "ios", label: "iOS" },
{ value: "youtube", label: "Youtube" },
{ value: "twitter", label: "Twitter" }
];
type ProjectLinks = [
{ web?: string },
{ android?: string },
{ ios?: string },
{ youtube?: string },
{ twitter?: string }
];
export default function App() {
const [count, setCount] = useState(1);
const [urlError, setUrlError] = useState(false);
const submit = (event: any) => {
let urlTypeArray: string[] = [];
let urlArray: string[] = [];
let projectLinks: ProjectLinks[] = [];
[...Array(count)].map((_, index) => {
let url =
count === 1 ? event.target.url.value : event.target.url[index].value;
let urlType =
count === 1
? event.target.urlType.value
: event.target.urlType[index].value;
if (
urlTypeArray.includes(urlType) ||
urlArray.includes(url) ||
!url.length
) {
setUrlError(true);
return null;
} else {
urlTypeArray.push(urlType);
urlArray.push(url);
var urlObj: any = {};
urlObj[urlType] = url;
projectLinks = [...projectLinks, urlObj];
}
});
if (!urlError && projectLinks.length) {
console.log(projectLinks);
// Action for URL submit to API
}
event.preventDefault();
};
const handleAddLink = () => {
setCount((prev) => (prev < linkOptions.length ? prev + 1 : prev));
};
const handleRemoveLink = () => {
setCount((prev) => (prev > 1 ? prev - 1 : prev));
};
return (
<MainLayout>
<form className="flex flex-col" onSubmit={submit}>
{[...Array(count)].map((link, index) => (
<LinkField
key={index}
index={index}
handleAddLink={handleAddLink}
handleRemoveLink={handleRemoveLink}
/>
))}
<button
className={`btn ${urlError ? "btn-disabled" : "btn-active"} mt-8`}
>
Button
</button>
{urlError ? (
<div
className="toast cursor-pointer"
onClick={() => setUrlError(false)}
>
<div className="alert alert-error">
<span>Duplicate URL Type or URL or URL is Empty.</span>
</div>
</div>
) : null}
</form>
</MainLayout>
);
}
function LinkField({
handleAddLink,
handleRemoveLink,
index
}: {
handleAddLink: () => void;
handleRemoveLink: () => void;
index: number;
}) {
return (
<div className="mt-1 mb-1">
<div className="flex justify-between">
<select name="urlType" className="select select-primary">
{linkOptions.map((option, index) => (
<option key={index} value={option.value}>
{option.label}
</option>
))}
</select>
<input
type="text"
name="url"
placeholder="example.com"
className="input input-bordered ml-1 mr-1"
/>
<button
className={`btn ${
index === linkOptions.length - 1 ? "btn-disabled" : ""
} ml-1 mr-1`}
onClick={handleAddLink}
type="button"
>
Add
</button>
<button
className={`btn ${index === 0 ? "btn-disabled" : ""} ml-1 mr-1`}
onClick={handleRemoveLink}
// type="button"
>
Remove
</button>
</div>
</div>
);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论