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

React状态更新未触发重渲染 POST成功需刷新才显示新数据

问题根因

页面提交后不自动更新和React状态引用更新规则无关,核心是4处代码逻辑错误:

  • AllChats组件拉取聊天列表的逻辑写在依赖为空的useEffect里,仅在组件首次加载时执行一次,表单提交成功后没有任何触发列表重新拉取的逻辑,自然不会展示新数据。
  • Form组件的chatData初始状态类型错误:初始值定义为数组[{chat: Number, isConverted: Boolean}],后续更新时却按普通对象处理,会导致表单取值、提交数据结构异常。
  • 提交逻辑没有等待POST请求执行完成,也没有在请求成功后执行任何联动操作,同时表单Select同时绑定defaultValue和value,违反受控组件使用规则,会产生取值异常。
  • 附加小问题:AllChats组件表格单元格属性拼写错误omponent="th",会导致DOM渲染异常。
修复步骤

1. 改造App组件,打通跨组件刷新链路

把列表刷新的触发能力下沉到父组件,表单提交成功后触发列表刷新:

import { useState, useCallback } from 'react'
import AllChats from './AllChats'
import Form from './Form'

function App() {
  const [refreshKey, setRefreshKey] = useState(0)
  const triggerListRefresh = useCallback(() => {
    setRefreshKey(prev => prev + 1)
  }, [])

  return (
    <>
      <AllChats refreshKey={refreshKey} />
      <Form onSubmitSuccess={triggerListRefresh} />
    </>
  )
}

export default App

2. 修复Form组件逻辑

修正初始状态类型,移除Select多余的defaultValue属性,等待POST请求完成后触发刷新、重置表单:

import { useState } from 'react'
import { Box, FormControl, InputLabel, Select, MenuItem, Button } from '@mui/material'
import axios from 'axios'

export default function Form ({ onSubmitSuccess }) {
  // 修正初始状态为普通对象,设置合法初始值
  const [chatData, setChatData] = useState({
    chat: '',
    isConverted: ''
  })

  const changeHandler = name => (e) => {
    setChatData(prev => ({...prev, [name]: e.target.value}))
  }

  const createChat = async (e) =>  {
    e.preventDefault()
    if (chatData.chat === '' || chatData.isConverted === '') return
    try {
      // 等待接口请求完成,转换字段为后端需要的正确类型
      await axios.post("/api/create", {
        chat: Number(chatData.chat),
        isConverted: chatData.isConverted === 'true'
      })
      // 提交成功触发列表刷新
      onSubmitSuccess?.()
      // 重置表单
      setChatData({ chat: '', isConverted: '' })
    } catch (error) {
      console.error('提交失败:', error)
    }
  }

  return (
    <div>
      <Box sx={{maxWidth: 200}} display="flex" alignItems="center" justifyContent="center" margin="auto">
        <form onSubmit={createChat}> 
          <FormControl fullWidth sx={{ m: 1, minWidth: 120 }}>
            <InputLabel id="chat_number_label">Chat Number</InputLabel>
            <Select
              labelId="chat_number_label"
              id="chat_input_select"
              value={chatData.chat}
              onChange={changeHandler("chat")}
              name="chat"
              label="Chat Number"
            >
              {Array.from({length:10}, (_,i) => i+1).map(num => (
                <MenuItem key={num} value={num}>{num}</MenuItem>
              ))}
            </Select>
          </FormControl>
          <FormControl fullWidth sx={{ m: 1, minWidth: 120 }}>
            <InputLabel id="is_converted_label">Converted to Ticket</InputLabel>
            <Select
              labelId="is_converted_label"
              id="is_converted_select"
              value={chatData.isConverted}
              onChange={changeHandler("isConverted")}
              name="isConverted"
              label="Converted to Ticket"
            >
              <MenuItem value={'true'}>True</MenuItem>
              <MenuItem value={'false'}>False</MenuItem>
            </Select>
          </FormControl>
          <Button color="primary" variant="contained" type="submit">Submit</Button>
        </form>
      </Box>
    </div>
  )
}

3. 修复AllChats组件逻辑

将父组件传入的refreshKey加入拉取数据的useEffect依赖,修正属性拼写错误:

import { useState, useEffect } from 'react'
import { Container, TableContainer, Paper, Table, TableHead, TableRow, TableCell, TableBody } from '@mui/material'
import { CSVLink } from 'react-csv'
import axios from 'axios'

export default function AllChats ({ refreshKey }) {
  const [chatList, setChatList] = useState([])

  useEffect(() => {
    const fetchAllChats = async () => {
      try {
        const res = await axios.get("/api")
        setChatList(res.data)
      } catch (error) {
        console.error('拉取列表失败:', error)
      }
    }
    fetchAllChats()
    // 依赖refreshKey,每次触发刷新时重新拉取列表
  }, [refreshKey])

  const headers = [
    { label: "Chat Number", key: "chat" },
    { label: "Date", key: "createdAt" },
    { label: "Converted into Ticket", key:"isConverted" }
  ]

  const csvLink = {
    filename: "chat_data.csv",
    headers: headers,
    data: chatList
  }

  return (
    <Container maxWidth="md">
      <TableContainer component={Paper}>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow>
              <TableCell>Chats Number</TableCell>
              <TableCell align="right">Date</TableCell>
              <TableCell align="right">Converted into ticket</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
          { chatList.map((val) => {
            return (
              <TableRow 
                key={val.chat}
                sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
              >
                {/* 修正拼写错误 */}
                <TableCell component="th" scope="row">{val.chat}</TableCell>
                <TableCell align="right">{val.createdAt}</TableCell>
                <TableCell align="right">{String(val.isConverted)}</TableCell>
              </TableRow>
            )
          })}
          </TableBody>
        </Table>
      </TableContainer>
      <CSVLink {...csvLink}>Export to CSV</CSVLink>
    </Container>
  )
}
注意事项
  • MUI的Select作为受控组件使用时,不要同时设置defaultValue和value,否则会抛出控制台警告,还可能导致取值不符合预期。
  • Select组件的onChange事件拿到的e.target.value默认是字符串类型,提交给后端前需要转换为接口要求的数字、布尔值类型,避免存入数据类型错误。
  • 异步请求必须加await等待执行完成后再执行后续逻辑,否则会出现请求还未写入数据库就触发列表拉取,拿到旧数据的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 11:54:15