React中如何从子组件修改父组件state?调用后state不更新如何解决
React子组件调用父组件传值方法未更新state的问题原因与解决方案
问题原因
- 未实际执行父组件传入的
logIn方法:Login子组件render方法中{this.props.logIn}只是将函数对象作为JSX内容输出,没有触发函数执行,自然不会触发父组件的setState操作。 - 登录按钮跳转逻辑优先于状态更新:LoginForm中的登录按钮被包裹在
Link组件内,点击后会直接跳转路由,没有预留执行logIn方法的时机。 - 子组件重复定义冗余逻辑(非直接故障原因,但属于高风险隐患):Login组件内部重复定义了
updateLanguage方法以及repos、selectedLanguage相关状态,和父组件传入的props逻辑冲突,容易导致数据不一致问题。
修复方案
1. 调整Login组件,透传logIn方法给LoginForm
修改Login组件代码,删除冗余的状态、请求逻辑,将父组件传入的logIn作为props透传给LoginForm:
export default class Login extends React.Component { // 可直接删除子组件内的constructor、componentDidMount、updateLanguage相关冗余代码 render() { const { selectedLanguage, repos, error, logIn } = this.props return ( <React.Fragment> {error && <p>{error}</p>} {repos && <LoginForm repos={repos} selected={selectedLanguage} logIn={logIn}/>} </React.Fragment> ) } }
2. 修改LoginForm的登录按钮逻辑,先执行状态更新再跳转
给登录按钮添加onClick事件触发logIn,取消外层Link的默认跳转,使用路由能力手动控制跳转时机:
// 函数组件可引入useHistory hook获取路由操作能力 import { useHistory } from 'react-router-dom' function LoginForm ({ repos, selected, logIn }) { const history = useHistory() // ... 原有变量定义、switch逻辑保持不变 return ( // ... 原有布局代码保持不变,仅修改登录按钮部分 <Button type="submit" fullWidth variant="contained" sx={{ mt: 3, mb: 2 }} onClick={(e) => { e.preventDefault() // 阻止表单默认提交行为 logIn() // 调用父组件传入的登录方法更新父组件state history.push({ pathname: '/dashboard', search: `?lang=${selected}` }) // 执行完状态更新后手动触发路由跳转 }} > {language.login} </Button> // 删除原按钮外层包裹的Link组件 ) }
3. 可选优化
父组件已经完成了语言切换、仓库数据请求的逻辑,并且通过props传入了Login组件,子组件直接使用props传入的值即可,无需重复实现相同逻辑,避免重复请求和数据不一致问题。
内容的提问来源于stack exchange,提问作者Julen Clarke
相关产品推荐
相关产品推荐

