
本文详解如何在 react 的父子组件通信中,借助回调函数与状态提升,实现在点击“添加题目”按钮前校验所有已存在子表单(questionform)的必填字段是否完整,并仅在全部有效时动态添加新题目。
要在
✅ 正确做法如下:
1. 父组件管理完整表单状态
将每个题目的所有字段(question、answerOne~Four、correctAnswer)作为对象存入 questionsArray,初始值可设为空字符串或 null:
const [questionsArray, setQuestionsArray] = useState([
{
id: nanoid(),
question: '',
answerOne: '',
answerTwo: '',
answerThree: '',
answerFour: '',
correctAnswer: '',
}
]);2. 向子组件传递更新回调(关键!)
为每个
{questionsArray.map((question) => (
setQuestionsArray(prev =>
prev.map(q =>
q.id === question.id ? { ...q, [field]: value } : q
)
)
}
/>
))} 3. 在 addQuestion 中执行完整性校验
校验逻辑:确保所有已有题目的 question 和 correctAnswer 非空(其他答案项可选,按需调整):
const addQuestion = () => {
// 校验:所有已有题目必须至少填了题干和正确答案
const hasIncomplete = questionsArray.some(q =>
!q.question.trim() || !q.correctAnswer.trim()
);
if (hasIncomplete) {
alert('请先完成所有已有题目的题干和正确答案!');
return;
}
// 校验通过,添加新空题目
setQuestionsArray(prev => [
...prev,
{
id: nanoid(),
question: '',
answerOne: '',
answerTwo: '',
answerThree: '',
answerFour: '',
correctAnswer: '',
}
]);
};4. 子组件(QuestionForm)示例实现要点
function QuestionForm({ id, data, onFieldChange }) {
return (
onFieldChange('question', e.target.value)}
/>
{/* 其他 input 同理... */}
);
}⚠️ 注意事项:
- 避免在子组件内维护独立 state(如 useState),否则父组件无法感知其真实值,导致校验失效;
- 若需实时反馈(如高亮未填字段),可在父组件中基于 questionsArray 计算 isInvalid 状态并透传给子组件;
- 对于大型表单,可考虑使用 useReducer 或 Zustand 等状态管理方案提升可维护性。
通过该设计,你既保持了组件职责清晰(子组件专注 UI 交互,父组件专注状态与业务逻辑),又实现了点击前强校验,真正做到了“优雅、可控、可扩展”。










