React表单提交后h1元素未更新?组件重渲染问题排查
问题描述
- 开发React组件时接入Material UI文本表单,通过
useStateHook维护输入框的输入状态 - 预期逻辑:表单提交时,将输入值赋值给
headingText变量,驱动页面h1元素更新显示对应内容 - 实际异常:h1元素始终显示初始值
Hello World未触发更新,通过控制台日志打印可确认headingText、输入框状态值均已被正常修改 - 问题复现代码:
import React, { useState } from 'react'; import CssBaseline from '@mui/material/CssBaseline'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import Alert from '@mui/material/Alert'; import { TextField } from '@mui/material'; import Button from '@mui/material/Button'; import './style.css'; import { useEffect } from 'react'; const darkTheme = createTheme({ palette: { mode: 'dark', }, }); export default function App() { const [myValue, setValue] = useState('') // The original hook let headingText = 'Hello World' let onSubmit = (e) => { e.preventDefault(); headingText = myValue; console.log(headingText); console.log(myValue); }; return ( <> <title>Text Changer</title> <div className='joe'> <ThemeProvider theme={darkTheme}> <React.Fragment> <CssBaseline /> <Alert severity="success">Page Loaded</Alert> <h1>{headingText}</h1> // the h1 I want to update <form onSubmit={onSubmit}> <TextField id="outlined-basic" label="Search Text" variant="outlined" value={myValue} onChange={(e) => setValue(e.target.value)}/> <br /> <br /> <Button variant="contained" color="primary" type="submit">Submit</Button> </form> </React.Fragment> </ThemeProvider> </div> </> ); }
问题根因
React组件的重渲染只会被三类操作触发:
- 组件自身的state通过对应的setter函数更新
- 组件接收的props发生变更
- 组件订阅的context值发生变更
你代码中的headingText是组件函数内部通过let声明的普通局部变量,不属于React追踪的响应式状态:
- 表单提交时给
headingText赋值的操作,不会触发组件重渲染流程 - 就算后续因为其他原因触发组件重渲染,组件函数重新执行时,
headingText会被再次初始化为'Hello World',之前的赋值操作会直接丢失
这就是为什么控制台能打印到修改后的值,但页面h1始终不更新的原因。
修复方案
所有需要驱动视图更新的动态值,都必须纳入React的响应式状态管理,不要用普通局部变量存储视图依赖的值。把headingText改为通过useState声明的状态,提交表单时通过对应的setter函数更新值即可,修复后完整代码如下:
import React, { useState } from 'react'; import CssBaseline from '@mui/material/CssBaseline'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import Alert from '@mui/material/Alert'; import { TextField } from '@mui/material'; import Button from '@mui/material/Button'; import './style.css'; const darkTheme = createTheme({ palette: { mode: 'dark', }, }); export default function App() { const [myValue, setValue] = useState('') // 将渲染依赖的动态值改为state管理 const [headingText, setHeadingText] = useState('Hello World') const onSubmit = (e) => { e.preventDefault(); // 通过state setter更新值,自动触发组件重渲染 setHeadingText(myValue); }; return ( <> <title>Text Changer</title> <div className='joe'> <ThemeProvider theme={darkTheme}> <React.Fragment> <CssBaseline /> <Alert severity="success">Page Loaded</Alert> <h1>{headingText}</h1> <form onSubmit={onSubmit}> <TextField id="outlined-basic" label="Search Text" variant="outlined" value={myValue} onChange={(e) => setValue(e.target.value)}/> <br /> <br /> <Button variant="contained" color="primary" type="submit">Submit</Button> </form> </React.Fragment> </ThemeProvider> </div> </> ); }
内容的提问来源于stack exchange,提问作者codenaem
相关产品推荐
相关产品推荐

