如何在React中从select-option中传递key:value的onChange?

huangapple go评论72阅读模式
英文:

How to pass key:value onChange from select-option in reactjs?

问题

我遵循了这个教程并尝试进行了一些修改。

我有这段代码 addRequestForm.js

import { BiPlus } from 'react-icons/bi'
import { useMutation, useQueryClient } from "react-query"
import { addRequest, getRequests } from "../../lib/helper"
import Bug from "./bugRequest"
import Success from "./successRequest"

export default function AddRequestForm({ formData, setFormData }) {

    const queryClient = useQueryClient()
    const addMutation = useMutation(addRequest, {
        onSuccess: () => {
            queryClient.prefetchQuery('requests', getRequests)
        }
    })

    const handleSubmit = (e) => {
        e.preventDefault();
        if (Object.keys(formData).length == 0) return console.log("Don't have Form Data");
        let { sector, contact_name } = formData;

        const model = {
            sector, contact_name
        }

        addMutation.mutate(model)
    }

    if (addMutation.isLoading) return <div>Loading!</div>
    if (addMutation.isError) return <Bug message={addMutation.error.message}></Bug>
    if (addMutation.isSuccess) return <Success message={"Added Successfully"}></Success>

    return (
        <form className="grid lg:grid-cols-2 w-4/6 gap-4 md:px-4 md:mx-auto" onSubmit={handleSubmit}>

            <div className="input-type">
                <label htmlFor="sector" className="block text-sm font-medium text-gray-700">
                    Sector
                </label>
                <select
                    id="sector"
                    name="sector"
                    autoComplete="sector-name"
                    className="border w-full px-5 py-3 focus:outline-none rounded-md"
                    onChange={(e) => setFormData({ [e.target.name]: e.target.value })}
                >
                    <option value="North">North</option>
                    <option value="South">South</option>
                    <option value="West">West</option>
                    <option value="East">East</option>
                </select>
            </div>

            <div className="form-control input-type">
                <label className="input-group">
                    <span>Contact Name</span>
                    <input type="text" onChange={setFormData} name="contact_name" placeholder="Contact Name Here.." className="w-full input input-bordered" />
                </label>
            </div>

            <button type="submit" className="flex justify-center text-md w-2/6 bg-green-500 text-white px-4 py-2 border rounded-md hover:bg-gray-50 hover:border-green-500 hover:text-green-500">
                Add <span className="px-1"><BiPlus size={24}></BiPlus></span>
            </button>

        </form>
    )
}

对于 name="contact_name",已成功插入到数据库(mongodb + mongoose)。但是,我仍然困惑如何对 select 元素执行相同的操作。

已尝试以下操作:

onChange={(e) => setFormData({ e.target.name: e.target.value })}
onChange={(e) => setFormData({ sector.name: e.target.value })}
onChange={(e) => setFormData({ [e.target.name][0]: e.target.value })}

出现语法错误:Unexpected token,expected ","。虽然我认为这是正确的值,当我将其打印出来时(结果:"sector:myname")。

onChange={(e) => setFormData({ sector: e.target.value })}
onChange={(e) => setFormData({ [e.target.name]: e.target.value })}

没有插入到数据库。

如何正确编写它?我正在使用 Next.js(我认为与 React.js 相同,对吗?)+ @reduxjs/toolkit 1.9.1。

如果需要,这是 reducer.js

import UpdateRequestForm from "./updateRequestForm";
import AddRequestForm from "./addRequestForm";
import { useSelector } from "react-redux";
import { useReducer } from "react";

const formReducer = (state, event) => {
    return {
        ...state,
        [event.target?.name]: event.target?.value
    }
}

export default function FormRequest() {

    const [formData, setFormData] = useReducer(formReducer, {})
    const formId = useSelector((state) => state.app.client.formId)

    return (
        <div className="container mx-auto py-5">
            {formId ? UpdateRequestForm({ formId, formData, setFormData }) : AddRequestForm({ formData, setFormData })}
        </div>
    )
}
英文:

I follow this tutorial and try to modify it a little.

I have this code addRequestForm.js

import { BiPlus } from &#39;react-icons/bi&#39;
import { useMutation, useQueryClient } from &quot;react-query&quot;
import { addRequest, getRequests } from &quot;../../lib/helper&quot;
import Bug from &quot;./bugRequest&quot;
import Success from &quot;./successRequest&quot;
export default function AddRequestForm({ formData, setFormData }) {
const queryClient = useQueryClient()
const addMutation = useMutation(addRequest, {
onSuccess: () =&gt; {
queryClient.prefetchQuery(&#39;requests&#39;, getRequests)
}
})
const handleSubmit = (e) =&gt; {
e.preventDefault();
if (Object.keys(formData).length == 0) return console.log(&quot;Don&#39;t have Form Data&quot;);
let { sector, contact_name } = formData;
const model = {
sector, contact_name
}
addMutation.mutate(model)
}
if (addMutation.isLoading) return &lt;div&gt;Loading!&lt;/div&gt;
if (addMutation.isError) return &lt;Bug message={addMutation.error.message}&gt;&lt;/Bug&gt;
if (addMutation.isSuccess) return &lt;Success message={&quot;Added Successfully&quot;}&gt;&lt;/Success&gt;
return (
&lt;form className=&quot;grid lg:grid-cols-2 w-4/6 gap-4 md:px-4 md:mx-auto&quot; onSubmit={handleSubmit}&gt;
&lt;div className=&quot;input-type&quot;&gt;
&lt;label htmlFor=&quot;sector&quot; className=&quot;block text-sm font-medium text-gray-700&quot;&gt;
Sector
&lt;/label&gt;
&lt;select
id=&quot;sector&quot;
name=&quot;sector&quot;
autoComplete=&quot;sector-name&quot;
className=&quot;border w-full px-5 py-3 focus:outline-none rounded-md&quot;
onChange={(e) =&gt; setFormData({ [e.target.name]: e.target.value })}
&gt;
&lt;option value=&quot;North&quot;&gt;North&lt;/option&gt;
&lt;option value=&quot;South&quot;&gt;South&lt;/option&gt;
&lt;option value=&quot;West&quot;&gt;West&lt;/option&gt;
&lt;option value=&quot;East&quot;&gt;East&lt;/option&gt;
{/*  */}
&lt;/select&gt;
&lt;/div&gt;
&lt;div className=&quot;form-control input-type&quot;&gt;
&lt;label className=&quot;input-group&quot;&gt;
&lt;span&gt;Contact Name&lt;/span&gt;
&lt;input type=&quot;text&quot; onChange={setFormData} name=&quot;contact_name&quot; placeholder=&quot;Contact Name Here..“ className=&quot;w-full input input-bordered&quot; /&gt;
&lt;/label&gt;
&lt;/div&gt;
&lt;button type=&quot;submit&quot; className=&quot;flex justify-center text-md w-2/6 bg-green-500 text-white px-4 py-2 border rounded-md hover:bg-gray-50 hover:border-green-500 hover:text-green-500&quot;&gt;
Add &lt;span className=&quot;px-1&quot;&gt;&lt;BiPlus size={24}&gt;&lt;/BiPlus&gt;&lt;/span&gt;
&lt;/button&gt;
&lt;/form &gt;
)
}

For name=“contact_name” already succeed insert into database (mongodb + mongoose). But, I’m still confuse, how to do the same to select-option?

Already tried these:

onChange={(e) =&gt; setFormData({ e.target.name: e.target.value })}
onChange={(e) =&gt; setFormData({ sector.name: e.target.value })}
onChange={(e) =&gt; setFormData({ [e.target.name][0]: e.target.value })}

Got Syntax error: Unexpected token, expected ",". While I thought this is the right value when I’m consoling these ( result: “sector:myname”).

onChange={(e) =&gt; setFormData({ sector: e.target.value })}
onChange={(e) =&gt; setFormData({ [e.target.name]: e.target.value })}

No insert into database.

How to write it correctly? I’m using nextjs (i thought the same with reactjs, right?) + @reduxjs/toolkit 1.9.1.

In case needed, here is reducer.js:

import UpdateRequestForm from &quot;./updateRequestForm&quot;;
import AddRequestForm from &quot;./addRequestForm&quot;;
import { useSelector } from &quot;react-redux&quot;;
import { useReducer } from &quot;react&quot;;
const formReducer = (state, event) =&gt; {
return {
...state,
[event.target?.name]: event.target?.value
}
}
export default function FormRequest() {
const [formData, setFormData] = useReducer(formReducer, {})
const formId = useSelector((state) =&gt; state.app.client.formId)
return (
&lt;div className=&quot;container mx-auto py-5&quot;&gt;
{formId ? UpdateRequestForm({ formId, formData, setFormData }) : AddRequestForm({ formData, setFormData })}
&lt;/div&gt;
)
}

答案1

得分: 0

onChange = {(e) => {
let obj = {} ;
obj[e.target.name] = e.target.value;
setFormData(obj);
}
}

英文:

try this

        onChange = {(e) =&gt; { 
let obj = {} ; 
obj[e.target.name] = e.target.value;
setFormData(obj);
} 
}

答案2

得分: 0

我并不完全理解您对reducer的使用情况,但您可以用以下的简单handleChange函数来替代它。只是一个小提示,调用setFormData(//newData)会完全擦除其中的内容,所以我们首先要展开原始状态,并根据key来更改值。

状态和handleChange函数:

const [formData, setFormData] = React.useState({
  sector: "North",
  contact_name: ""
});

const handleChange = ({ target }) => {
  // 解构目标对象
  // 从目标对象中解构名称和值
  const { name, value } = target;
  // 设置状态
  setFormData((previousState) => ({
    ...previousState,
    [name]: value,
  }));
};

用法:

<select
  placeholder="选择一个部门"
  name="sector"
  value={formData.sector}
  onChange={handleChange}
>
  <option value="North">北部</option>
  <option value="South">南部</option>
  <option value="West">西部</option>
  <option value="East">东部</option>
</select>

<input
  value={formData.contact_name}
  placeholder="联系人姓名"
  name="contact_name"
  onChange={handleChange}
/>

此外,请注意您需要为输入元素指定一个名称。在示例中,名称设置为sector。因为名称值将用于指示必须更新状态对象中的哪个键。

拥有受控输入字段是一种良好的做法。因此,将输入的值设置为状态将实现这一点。唯一需要记住的是您需要一个默认状态。如果您想查看,我已将所有内容添加到了codesandbox中。

英文:

I'm not entirely following your use case for the reducer but you could replace it with a simple handleChange function as follows. Just a side note, calling setFormData(//newData) will complete erase what is in there so we first spread the original state and change the value based on the key.

State and handleChange:

  const [formData, setFormData] = React.useState({
sector: &quot;North&quot;,
contact_name: &quot;&quot;
});
const handleChange = ({ target }) =&gt; {
// Deconstruct the target
// Deconstruct the name and value from the target
const { name, value } = target;
// Set the state
setFormData((previousState) =&gt; ({
...previousState,
[name]: value,
}));
};

Usage:

  &lt;select
placeholder=&quot;Select a sector&quot;
name=&quot;sector&quot;
value={formData.sector}
onChange={handleChange}
&gt;
&lt;option value=&quot;North&quot;&gt;North&lt;/option&gt;
&lt;option value=&quot;South&quot;&gt;South&lt;/option&gt;
&lt;option value=&quot;West&quot;&gt;West&lt;/option&gt;
&lt;option value=&quot;East&quot;&gt;East&lt;/option&gt;
&lt;/select&gt;
&lt;input
value={formData.contact_name}
placeholder=&quot;Contact Name&quot;
name=&quot;contact_name&quot;
onChange={handleChange}
/&gt;

A codesandbox : https://codesandbox.io/s/interesting-kilby-emcyl4?file=/src/App.js:461-615

Also note that you will need to assign a name to the input element. In the example, name is set to sector. As the name value will be used to indicate which key in the state object must be updated.

It's good practice to have controlled input fields. So setting the value of the input to your state will accomplish this. Only thing to remember is you need a default state. I have added it all to the codesandbox if you would like to take a look.

答案3

得分: 0

在我的情况下,只需使用以下语法:

…
value={formData.sector}
onChange={setFormData}
…

案件关闭。

英文:

In my case, just use this syntax:

…
value={formData.sector}
onChange={setFormData}
…

Case closed.

huangapple
  • 本文由 发表于 2023年1月6日 13:07:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75027132.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定