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

React事件提交后创建者名称显示Unknown问题求助

React事件详情页创建者显示“Unknown”问题排查与修复

问题描述

开发React事件添加应用,表单包含用户选择下拉菜单,填写信息后通过POST请求提交到http://localhost:3000/events,事件能成功创建并在列表中显示,但进入详情页后,创建者名称始终显示为“Unknown”,推测提交时用户信息未正确传递。

相关代码

表单组件代码

export const loader = async ({ params }) => {
  const categories = await fetch("http://localhost:3000/categories")
  const users = await fetch("http://localhost:3000/users")
  const event = await fetch("http://localhost:3000/events")

  return {
    event: await event.json(),
    categories: await categories.json(),
    users: await users.json()
  }
}

export const FormPage = () => {
  const [selectedCategories, setSelectedCategories] = useState([])
  const [selectedUser, setSelectedUser] = useState("") // 用户选择状态
  const [title, setTitle] = useState("")
  const [description, setDescription] = useState("")
  const [startTime, setStartTime] = useState(0)
  const [endTime, setEndTime] = useState(0)
  const [image, setImage] = useState("")
  //const [location, setLocation] = useState("")
  const [isPending, setIsPending] = useState(false)

  const navigate = useNavigate()
  const toast = useToast()

  const { categories, event, users } = useLoaderData()

  const showToast = () => {
    toast({
      title: "提交成功",
      description: "新事件已添加",
      duration: 3000,
      isClosable: true,
      status: "success",
      position: "top"
    })
  }

  const handleChange = e => {
    setSelectedUser(e.target.value)
  }

  const handleSubmit = async e => {
    e.preventDefault()
    const addEvent = {
      title: title,
      createdBy: selectedUser,   // 下拉选择的用户ID
      description: description,
      startTime: startTime,
      endTime: endTime,
      image: image,
      categoryIds: []
    }

    addEvent.categoryIds = selectedCategories

    setIsPending(true)

    try {
      fetch("http://localhost:3000/events", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(addEvent)
      })


      setIsPending(false)
      showToast()
      navigate("/")

      if (response.ok) {
        alert("资源更新成功")
        navigate("/")
      } else {
        alert("资源更新失败")
      }
    } catch (error) {
      console.error("错误:", error)
    }
  }

  return (
    <Box>
      <AbsoluteCenter>
        <Card>
          <form onSubmit={handleSubmit}>
            <CardBody>
              <div className="container-body">
                <p style={{ marginTop: "40px", marginLeft: "5px" }}>标题:</p>
                <input type="text" name="title" onChange={e => setTitle(e.target.value)} className="input-form" />
                <p style={{ marginLeft: "5px" }}>描述:</p>
                <textarea name="description" onChange={e => setDescription(e.target.value)} className="textarea-form"></textarea>
                <FilterBar activeCategories={selectedCategories} setActiveCategories={setSelectedCategories} categories={categories} />
                <input type="file" name="image" id="fileInput" accept="image/*" onChange={handleFileChange} />

                {/* 问题中的下拉菜单 */}
                <div>
                  <select onChange={handleChange} id="createdBy" value={selectedUser} required className="dropdown">
                    {users.map(user => (
                      <option key={user.id} value={user.id}>
                        {user.name}
                      </option>
                    ))}
                  </select>
                </div>


                <div className="container-date">
                  <div className="date-start">
                    <span>开始时间:</span>
                    <input className="input-date" type="datetime-local" onChange={e => setStartTime(e.target.value)} /> <br></br>
                  </div>

                  <div>
                    <span>结束时间:</span>
                    <input className="input-date" type="datetime-local" onChange={e => setEndTime(e.target.value)} />
                  </div>
                </div>
              </div>
            </CardBody>
            <Divider />
            <CardFooter className="footer-form">
              {!isPending && <CButton type="submit">提交</CButton>}
              {isPending && <CButton>添加事件中...</CButton>}
            </CardFooter>
          </form>
        </Card>
      </AbsoluteCenter>
    </Box>
  )
}

事件详情页组件代码

// 事件详情页组件
export const eventDetailsLoader = async ({ params }) => {
  const event = await fetch(`http://localhost:3000/events/${params.eventId}`)
  const categories = await fetch("http://localhost:3000/categories")
  const users = await fetch("http://localhost:3000/users")

  return {
    event: await event.json(),
    categories: await categories.json(),
    users: await users.json()
  }
}

export const EventPage = () => {
  const { event, categories, users } = useLoaderData()

  const categoryIds = Array.isArray(event.categoryIds) ? event.categoryIds : []
  const categoryNames = categoryIds.map(id => categories.find(category => category.id === id)?.name || "Unknown")

  const reverseString = date => {
    const splitDate = date.split("-")
    const reverseArray = splitDate.reverse()
    const joinArray = reverseArray.join("-")
    return joinArray
  }

  const user = users.find(user => user.id === event.createdBy) || {}
  const finalEvent = {
    ...event,
    date: reverseString((event.startTime || "").slice(0, 10).toString() || ""),
    startTime: event.startTime ? event.startTime.split("T")[1]?.slice(0, 5).toString() : "",
    endTime: event.endTime ? event.endTime.split("T")[1]?.slice(0, 5).toString() : "",
    categoryNames: categoryNames,
    userName: user.name || "Unknown",
    userImage: user.image || "DefaultImageURL"
  }

  const text = (label, content) => (
    <Flex>
      <Text fontStyle="italic" fontWeight="bold">
        {label}
        {":"}
      </Text>

      <Text style={{ marginLeft: "30px" }}>{content}</Text>
    </Flex>
  )

  const listItems = items => (
    <List>
      {items.map((item, index) => (
        <ListItem key={index}>{item}</ListItem>
      ))}
    </List>
  )

  return (
    <Center display="flex" flexDir="column">
      <Card minW={450} h="full" mt={300}>
        <CardHeader fontWeight="bold">
          <h1>{finalEvent.title}</h1>
          <CardHeader m={0} p={0}>
            <Flex flexDir="column" color="white">
              <Image src={finalEvent.image} w="75%" h="30em" />
            </Flex>
          </CardHeader>
        </CardHeader>

        <CardBody align="center">
          {text("活动内容", finalEvent.description)}
          {text("日期", finalEvent.date)}

          {text("时间", `${finalEvent.startTime} - ${finalEvent.endTime}h`)}
          {text("地点", finalEvent.location)}
        </CardBody>
        <hr />

        <CardFooter pl={-5} pr={0}>
          <Flex w="100%">
            <Box w="50%">
              <Tag size="lg" borderRadius="full" bgColor="white">
                <Avatar src={finalEvent.userImage} size="md" name={finalEvent.userName} ml={3} mr={3} />
                <TagLabel font={9}> {finalEvent.userName}</TagLabel>
              </Tag>
            </Box>
            <Spacer />

            <Box w="16.5%"></Box>
            <Spacer />

            <Spacer />
            <Box w="16.5%">
              <Link to="/">
                <Button colorScheme="purple" size="l" padding={4}>
                  返回
                </Button>
              </Link>
            </Box>
          </Flex>
        </CardFooter>
      </Card>
    </Center>
  )
}

问题排查与修复方案

1. 修复表单提交逻辑的响应处理错误

表单的handleSubmit函数中,fetch调用未等待响应,且response变量未定义,导致不管请求成功与否都会直接跳转。修改如下:

const handleSubmit = async e => {
  e.preventDefault()
  const addEvent = {
    title: title,
    createdBy: selectedUser,
    description: description,
    startTime: startTime,
    endTime: endTime,
    image: image,
    categoryIds: selectedCategories
  }

  setIsPending(true)

  try {
    // 等待fetch响应
    const response = await fetch("http://localhost:3000/events", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(addEvent)
    })

    if (response.ok) {
      setIsPending(false)
      showToast()
      alert("资源更新成功")
      navigate("/")
    } else {
      setIsPending(false)
      alert("资源更新失败")
    }
  } catch (error) {
    setIsPending(false)
    console.error("错误:", error)
    alert("提交失败,请重试")
  }
}

2. 修复用户ID类型不匹配问题

下拉菜单的value默认是字符串类型,若后端存储的user.id是数字类型,详情页中users.find(user => user.id === event.createdBy)会因类型不匹配返回undefined,导致显示“Unknown”。

方案一:提交时转换为数字
修改表单中addEvent的createdBy字段:

createdBy: Number(selectedUser),

方案二:详情页匹配时忽略类型
修改详情页中查找用户的逻辑:

const user = users.find(user => user.id == event.createdBy) || {}

3. 补充缺失的handleFileChange函数

表单中文件输入框绑定了handleFileChange但未定义,会导致图片上传功能失效,补充该函数:

const handleFileChange = e => {
  const file = e.target.files[0]
  if (file) {
    const reader = new FileReader()
    reader.onloadend = () => {
      setImage(reader.result)
    }
    reader.readAsDataURL(file)
  }
}

验证步骤

  1. 修复代码后重新启动应用
  2. 创建新事件并选择用户
  3. 进入事件详情页,确认创建者名称正常显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 13:55:54