You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript+React ContextAPI中setUser意外令牌错误修复及数据添加问题

问题描述

作为TypeScript新手,我正在使用React Context API维护用户对象数组,尝试将uploadState的信息合并到setUser时触发了Unexpected Token错误,无法将uploadState添加到用户数组中。相关代码如下:

ContextAPI代码

import { createContext, useState } from "react";
import { UserType } from "../Reducers/Upload";

type UserContextProviderType = {
  children: React.ReactNode;
};

const intionalState: UserType[] = [
  { name: "", phoneNumber: "", partyName: "", userImage: "" } as UserType,
];

type UserContextType = {
  user: UserType[];
  setUser: React.Dispatch<React.SetStateAction<UserType[]>>;
};
export const UserContext = createContext<UserContextType | null>(null);

export const UserState = ({ children }: UserContextProviderType) => {
  const [user, setUser] = useState<UserType[]>(intionalState);

  return (
    <UserContext.Provider value={{ user, setUser }}>
      {children}
    </UserContext.Provider>
  );
};

UserType定义

export type UserType = {
    name: string;
    phoneNumber: string;
    partyName: string;
    userImage: string;
};

UploadDetails组件代码(错误位置)

import { useContext, useReducer, useRef, useState } from "react";
import InputField from "../components/InputField";
import Button from "../components/Button";
import Image from "../components/Image";
import CommonStyle from "../Style/CommonStyle.module.css";
import UploadStyle from "../Style/UploadDetails.module.css";
import { intionalUploadState, uploadReducer } from "../Reducers/UploadReducer";
import defaultPic from "../assets/defaultPic.png";
import { UserContext } from "../context/UserContext";


export default function UploadDetails() {
  const inputRef = useRef<HTMLInputElement>(null);
  const [image, setImage] = useState<string>(defaultPic);
  const [uploadState, dispatch] = useReducer(
    uploadReducer,
    intionalUploadState
  );

  const context = useContext(UserContext)

  const handleClick = (event: React.MouseEvent) => {
    event.preventDefault();
    context?.setUser(prev => {return [...prev, {...context.user? ,context.user?.concate[uploadState]}]})

  };

  
const imageUpload = () => {
    inputRef.current?.click();
  };

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    switch (event.target.name) {
      case "name":
        dispatch({ type: event.target.name, payload: event.target.value });
        break;
      case "phoneNumber":
        dispatch({ type: event.target.name, payload: event.target.value });
        break;
      case "partyName":
        dispatch({ type: event.target.name, payload: event.target.value });
        break;
      case "userImage":
        dispatch({ type: event.target.name, payload: event.target.value });
        setImage(URL.createObjectURL(event.target.files![0]));
        console.log(uploadState);
        break;
      default:
        return uploadState;
    }
  };

  return (
    <>
      <div className={UploadStyle.container}>
        <h2 className={CommonStyle.header} style={{marginTop: "1rem"}}>Enter Details</h2>
        <div className={UploadStyle.detailsSection}>
          <div className={UploadStyle.textSection}>
            <InputField
              type="text"
              name="candidateName"
              placeholder="Enter Name"
              styles={CommonStyle.commonInput}
              handleChange={handleChange}
            />
            <InputField
              type="text"
              name="phoneNumber"
              placeholder="Enter PhoneNumber"
              styles={CommonStyle.commonInput}
              handleChange={handleChange}
            />
            <InputField
              type="text"
              name="PartyName"
              placeholder="Enter Party Name"
              styles={CommonStyle.commonInput}
              handleChange={handleChange}
            />
          </div>
          <div className={UploadStyle.imageSection}>
            <input
              type="file"
              name="imageInput"
              className={UploadStyle.imageInput}
              ref={inputRef}
              onChange={handleChange}
            />
            <Image source={image} styles={UploadStyle.imageUpload} />
            <Button
              name="Upload Image"
              styles={UploadStyle.button}
              type="button"
              handleSubmit={imageUpload}
            />
          </div>
        </div>
        <Button name="Submit" styles={CommonStyle.button} type="button" handleSubmit={handleClick}/>
      </div>
    </>
  );
}

Reducer代码

import { UserType } from "./Upload";

export const intionalUploadState: UserType = {
  name: "",
  phoneNumber: "",
  partyName: "",
  userImage: "",
};

type UploadStateType = {
  type: "name" | "phoneNumber" | "partyName" | "userImage";
  payload: string;
};

export const uploadReducer = (
  state: UserType,
  action: UploadStateType
) => {
  switch (action.type) {
    case "name":
      return { ...state, name: action.payload };
    case "phoneNumber":
      return { ...state, phoneNumber: action.payload };
    case "partyName":
      return { ...state, partyName: action.payload };
    case "userImage":
      return { ...state, userImage: action.payload };
    default:
      return state;
  }
};
错误原因与修复方案

1. 修复handleClick中的语法与逻辑错误

原代码中的setUser回调存在多个问题:

  • 无效的可选链语法...context.user?
  • 数组方法拼写错误concate(正确应为concat)
  • 错误依赖context.user而非prev参数(React状态更新需依赖prevState保证最新值)

修复后的handleClick:

const handleClick = (event: React.MouseEvent) => {
  event.preventDefault();
  // 直接将uploadState添加到prev数组末尾,创建新数组
  context?.setUser(prev => [...prev, uploadState]);
};

如果需要避免引用问题,可复制uploadState对象:

const handleClick = (event: React.MouseEvent) => {
  event.preventDefault();
  context?.setUser(prev => [...prev, {...uploadState}]);
};

2. 修复InputField的name属性不匹配

原组件中InputField的name与reducer的type不匹配,导致无法正确更新uploadState:

  • 将第一个InputField的name="candidateName"改为name="name"
  • 将第三个InputField的name="PartyName"改为name="partyName"

修复后的代码片段:

<InputField
  type="text"
  name="name"
  placeholder="Enter Name"
  styles={CommonStyle.commonInput}
  handleChange={handleChange}
/>
<!-- 中间代码省略 -->
<InputField
  type="text"
  name="partyName"
  placeholder="Enter Party Name"
  styles={CommonStyle.commonInput}
  handleChange={handleChange}
/>

3. 修复文件输入框的name属性不匹配

原文件输入框的name="imageInput"与handleChange中判断的userImage不匹配,导致无法更新uploadState.userImage:

<input
  type="file"
  name="userImage"
  className={UploadStyle.imageInput}
  ref={inputRef}
  onChange={handleChange}
/>

额外优化建议

  • 添加表单验证:在handleClick中检查uploadState的字段是否为空,避免添加无效用户数据
  • 重置上传状态:添加用户后,可在reducer中新增重置action,将uploadState恢复为初始值,方便下次输入

内容的提问来源于stack exchange,提问作者Kapil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 00:38:08