React子组件向父组件传值时出现JSX组件报错该如何解决
问题原因
你出现报错的核心原因是混淆了两种React组件的使用模式:普通JSX组件要求返回合法的JSX元素,但你当前的GameAnswers返回的是包含selectedAnswer和render属性的对象,不符合JSX组件的返回要求,因此TS抛出类型错误。
视频方案的可行性
2021年那则教程的方案是可行的,它本质是自定义Hook+返回渲染函数的模式,并非普通JSX组件,你误解了它的调用方式。
两种修复方案
方案1:沿用教程的自定义Hook模式
将GameAnswers改为自定义Hook(按照React规范Hook名必须以use开头),在父组件中手动调用Hook拿到状态和渲染结构:
- 修改
GameAnswers.tsx的文件名和函数名,改为useGameAnswers.tsx:
import React, { useState } from 'react'; import { ToggleButtonGroup, ToggleButton } from 'react-bootstrap'; import './css/GameAnswers.css'; type Answers = { arrayAnswers: Array<string>, correctAnswer: string } // 改为自定义Hook export default function useGameAnswers(props: Answers) { const [selectedAnswer, setSelectedAnswer] = useState(""); const handleAnswerChange = function (e: React.ChangeEvent<HTMLInputElement>) { setSelectedAnswer(e.target.value); } const determineButtonVariant = function (answer: string) { if (answer !== selectedAnswer) { return "primary"; } else if (answer === props.correctAnswer) { return "success"; } else { return "danger"; } } return { selectedAnswer, render: ( <div className="game-answers"> <ToggleButtonGroup type="radio" name="answers"> {props.arrayAnswers.map(function (answer) { // 补充缺失的key属性 return <ToggleButton key={answer} id={answer} value={answer} onChange={handleAnswerChange} variant={determineButtonVariant(answer)} >{answer}</ToggleButton> })} </ToggleButtonGroup> </div> ) } }
- 父组件调用方式:
// 父组件内调用 import useGameAnswers from './useGameAnswers'; function ParentComponent() { // 调用Hook拿到状态和渲染结构 const { selectedAnswer, render } = useGameAnswers({ arrayAnswers: ['Yes', 'No'], correctAnswer: 'Yes' }); // 这里直接可以拿到子组件的选中值,实现子传父 console.log('选中的答案:', selectedAnswer); return ( <div> {/* 渲染组件UI */} {render} </div> ) }
方案2:改为普通JSX组件(更符合常规开发习惯)
如果你更习惯用普通标签调用组件,可以直接给组件加回调props实现子传父:
- 修改
GameAnswers.tsx代码:
import React, { useState } from 'react'; import { ToggleButtonGroup, ToggleButton } from 'react-bootstrap'; import './css/GameAnswers.css'; type Answers = { arrayAnswers: Array<string>, correctAnswer: string, // 新增回调props,用于向父组件传值 onAnswerChange: (answer: string) => void } function GameAnswers(props: Answers) { const [selectedAnswer, setSelectedAnswer] = useState(""); const handleAnswerChange = function (e: React.ChangeEvent<HTMLInputElement>) { const val = e.target.value; setSelectedAnswer(val); // 选中值变更时触发父组件传入的回调 props.onAnswerChange(val); } const determineButtonVariant = function (answer: string) { if (answer !== selectedAnswer) { return "primary"; } else if (answer === props.correctAnswer) { return "success"; } else { return "danger"; } } // 直接返回JSX,不要返回对象 return ( <div className="game-answers"> <ToggleButtonGroup type="radio" name="answers"> {props.arrayAnswers.map(function (answer) { return <ToggleButton key={answer} id={answer} value={answer} onChange={handleAnswerChange} variant={determineButtonVariant(answer)} >{answer}</ToggleButton> })} </ToggleButtonGroup> </div> ) } export default GameAnswers;
- 父组件调用方式:
<GameAnswers arrayAnswers={['Yes', 'No']} correctAnswer="Yes" onAnswerChange={(val) => { // 父组件直接拿到子组件传的选中值 console.log('父组件拿到的答案:', val); }} />
内容的提问来源于stack exchange,提问作者user14399919
相关产品推荐
相关产品推荐

