从子组件传递时,FormData 在父组件中为空
Posted
技术标签:
【中文标题】从子组件传递时,FormData 在父组件中为空【英文标题】:FormData is empty in parent when passed from child component 【发布时间】:2022-01-01 18:54:08 【问题描述】:初学者警报! :) 我在子组件中设置 FormData,然后使用 formReducer 和调度将其传递给父组件,但在父组件中 formData.entries() 始终为空!
ChildComponent.js
function ChildComponent(signed, fileAttached)
const dispatch = useContext(ContactFormContext);
const changeHandler = (event) =>
const formData = new FormData();
formData.append('File', event.target.files[0]);
dispatch( type: "FILE_ATTACHED", payload: formData )
;
return (
<>
<div>
<input type="file" name="file" onChange=changeHandler />
</div>
</>);
父组件.js
function useFormProgress(fileAttached)
function goForward()
const currentStep = 1;
let appvariables = [
"key": "PUID",
"value": "a2sd"
,
"key": "ApplicationNames",
"value": "Trello, abc"
];
switch(currentStep)
case 0:
break;
case 1:
console.log(fileAttached);
if(fileAttached != null)
sendEmail("Resignation Letter", appvariables, fileAttached);
break;
return [goForward];
function sendEmail(templateName, variables, attachment)
console.log("sending email...");
const requestBody =
"templateName": templateName,
"recipients": [
"abc@xyz.com"
],
"variables": variables,
"files": attachment
;
fetch('https://localhost:5001/api/Email',
method:'Post',
body: JSON.stringify(requestBody),
headers:'Content-Type': 'application/json',
);
const initialState =
signed: "",
fileAttached: null
;
function formReducer(state, action)
switch (action.type)
case "SIGNED":
return ...state, signed: action.payload ;
case "FILE_ATTACHED":
return ...state, fileAttached: action.payload;
default:
throw new Error();
function ParentComponent()
const [state, dispatch] = useReducer(formReducer, initialState);
const signed, fileAttached = state;
const steps = [<ChildComponent ...signed, fileAttached/>];
const [goForward] = useFormProgress(fileAttached);
return (
<ContactFormContext.Provider value= dispatch >
<div>steps[0]
<div><button onClick=e =>
e.preventDefault();
goForward();
> Parent Button
</button>
</div>
</div>
</ContactFormContext.Provider>
);
ContactFormContext.js
const ContactFormContext = React.createContext();
在上面的switch语句(ParentComponent)中,console.log(FileAttached)显示FormData有0个条目(见附图),API请求也不成功!
你可以在https://jscomplete.com/playground试试看
在顶部添加上下文
添加子组件代码
添加父组件代码
添加以下行
ReactDOM.render(<ParentComponent/>, mountNode);
MyAPI 方法
[HttpPost]
public JsonResult Get(EmailRequest email)
//the request never comes here
EmailRequest.cs
public class EmailRequest
public string TemplateName get; set;
public string[] Recipients get; set;
public List<Variables> Variables get; set;
public FormFileCollection files get; set;
【问题讨论】:
在您将 ContactFormContext.Provider 中的 ChildComponent 渲染为子组件的 ParentComponent 中? 抱歉让我补充一下 你能和我们分享一下ContactFormContext吗? 发送上下文文件内容由我模拟到codesandbox中 添加的上下文文件内容它真的是一个声明 - 尝试模仿它的 jsplayground 步骤 - 我还在 c# 中添加我的 api 方法签名 【参考方案1】:为了通过使用 console.log 从 FormData 的条目方法中获取值,您应该这样做:
for (var [key, value] of attachment.entries())
console.log("log from for loop", key, value);
此外,如果您想使用 POST 请求将文件发送到服务器,则无法对要发送的文件进行字符串化。您当前在 json 有效负载中发送的内容类似于 "files":
。您需要以不同的方式对其进行序列化。这意味着您需要更改发送此文件的方式。
检查这个问题的答案:
How do I upload a file with the JS fetch API?
FormData的序列化可以查看这个帖子:https://gomakethings.com/serializing-form-data-with-the-vanilla-js-formdata-object/
【讨论】:
【参考方案2】:我在代码沙箱中添加了您的代码,一切似乎都很好。
Codesandbox demo
【讨论】:
【参考方案3】:所以,从上面 Lazar Nikolic 的回答开始,停止尝试 json.stringify!.. 在这里和那里偶然发现一些阻止程序之后,我终于能够成功地将文件发送到 API!
以下是一些需要注意的重要步骤:
在后端 - 我更改了控制器方法:
添加 [FromForm] 标签
[HttpPost]
public JsonResult Get([FromForm] EmailRequest email)
This post 帮助了我。
在前端
将 ChildComponent.js 改成如下
function ChildComponent(signed, fileAttached)
const dispatch = useContext(ContactFormContext);
const changeHandler = (event) =>
dispatch( type: "FILE_ATTACHED", payload: event.target.files[0] )
;
return (
<>
<div>
<input type="file" name="file" onChange=changeHandler />
</div>
</>);
ParentComponent.js 中的 sendEmail 函数修改如下
function sendEmail(templateName, variables, attachment)
console.log("sending email...");
const formData = new FormData();
formData.append('files', attachment);
formData.append('templateName', templateName);
formData.append('recipients', [
"abc@xyz.com"
]);
formData.append('variables', variables);
fetch('https://localhost:5001/api/Email',
method:'Post',
body: formData,
//headers:'Content-Type': 'application/json',
);
请注意,在我删除 Content-type 标头之前,收到的电子邮件对象的所有属性都设置为 null,然后浏览器将自己添加 multipart/form-data 标头。我从 @madhu131313 的评论 @ 中得到了帮助987654322@
我们不能直接在表单数据下传递一个对象数组,所以变量数组是空的..我做了以下
for(let i = 0; i < variables.length; i++)
formData.append(`variables[` + i + `].key`, variables[i].key);
formData.append(`variables[` + i + `].value`, variables[i].value);
而不是
formData.append('variables', variables);
并更改收件人如下:
let recipients = [
"abc@xyz.com",
"nop@xyz.com",
"stu@xyz.com"
];
for(let i = 0; i < recipients.length; i++)
formData.append(`recipients[` + i + `]`, recipients[i]);
【讨论】:
以上是关于从子组件传递时,FormData 在父组件中为空的主要内容,如果未能解决你的问题,请参考以下文章