React报错:对象不能作为React子元素,函数组件传参问题排查
报错信息
Uncaught Error: Objects are not valid as a React child (found: object with keys {message, showAlerts}). If you meant to render a collection of children, use an array instead.
父组件代码
import styled from "styled-components"; import { useTable } from "react-table"; import Alert from "react-bootstrap/Alert"; import Button from "react-bootstrap/Button"; import axios from "axios"; import AppAlerts from "./components/Alerts"; const Styles = styled.div` padding: 1rem; table { border-spacing: 0; border: 1px solid black; tr { :last-child { td { border-bottom: 0; } } } th, td { margin: 0; padding: 0.5rem; border-bottom: 1px solid black; border-right: 1px solid black; :last-child { border-right: 0; } } } `; function Table({ columns, data }) { // Use the state and functions returned from useTable to build your UI const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns, data }); const [showAlert, setShowAlert] = useState(false); const [alertMessage, setAlertMessage] = useState(""); const handleButttonClick = () => { setShowAlert(true); setAlertMessage("dummy text"); }; // Render the UI for table return ( <div> <div> <AppAlerts message={alertMessage} showAlerts={showAlert} />; </div> <table {...getTableProps()}> <thead> {headerGroups.map((headerGroup) => ( <tr {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map((column) => ( <th {...column.getHeaderProps()}>{column.render("Header")}</th> ))} </tr> ))} </thead> <tbody {...getTableBodyProps()}> {rows.map((row, i) => { prepareRow(row); return ( <tr {...row.getRowProps()}> {row.cells.map((cell) => { return ( <td {...cell.getCellProps()}>{cell.render("Cell")}</td> ); })} </tr> ); })} </tbody> </table> <Button onClick={handleButttonClick}>Open Alert box</Button> </div> ); } function App() { // const [data, setData] = useState([]); // const [columns, setColumns] = useState([]); const columns = React.useMemo( () => [ { Header: "Id", accessor: "id" }, { Header: "Applicant", accessor: "applicant" }, { Header: "Pincode", accessor: "pincode" }, { Header: "District", accessor: "district" }, { Header: "State", accessor: "state" } ], [] ); const data = React.useMemo( () => [ { id: 18, applicant: "Buzz", pincode: 560096, district: 1, state: 1 }, { id: 19, applicant: "Sue", pincode: 560100, district: 2, state: 1 } ], [] ); return ( <div className="App"> <Styles> <Table columns={columns} data={data} /> </Styles> </div> ); } export default App;
子组件代码
import { useEffect, useState } from "react"; import Alert from "react-bootstrap/Alert"; export default function AppAlerts(message, showAlerts) { const [show, setShow] = useState(showAlerts); return ( <Alert variant="info" onClose={() => setShow(false)} show={show} dismissible > <p>{message}</p> </Alert> ); }
提问
请问我哪里出错了,应该如何修改?我尝试以常规方式渲染Alert子组件,希望点击按钮时Alert弹出,关闭弹窗时父组件的showAlerts状态也同步变为false。
1. 渲染报错的原因及修复
React函数组件的props是单个对象参数,不是分开的独立参数。你的子组件AppAlerts写了function AppAlerts(message, showAlerts),这会导致第一个参数message实际上接收的是整个props对象(包含message和showAlerts两个键),第二个参数showAlerts是undefined。
当你在<p>{message}</p>里渲染这个对象时,React就会抛出“Objects are not valid as a React child”的错误。
修复方法:解构props对象,正确接收参数:
// 子组件修改为 export default function AppAlerts({ message, showAlerts, onClose }) { return ( <Alert variant="info" onClose={onClose} show={showAlerts} dismissible > <p>{message}</p> </Alert> ); }
2. 状态同步问题的修复
你现在的子组件自己维护了show状态,关闭弹窗时只会修改子组件内部的状态,父组件的showAlert不会同步更新。要实现父子状态同步,应该把状态控制权交给父组件:
- 父组件传递
setShowAlert的回调给子组件 - 子组件直接使用父组件的
showAlerts控制显示,关闭时调用父组件的回调更新状态
父组件修改:在渲染AppAlerts时传递关闭回调:
// Table组件的return里修改AppAlerts的调用 <AppAlerts message={alertMessage} showAlerts={showAlert} onClose={() => setShowAlert(false)} />
子组件修改:移除内部的show状态,直接使用父组件传入的showAlerts和onClose:
import Alert from "react-bootstrap/Alert"; export default function AppAlerts({ message, showAlerts, onClose }) { return ( <Alert variant="info" onClose={onClose} show={showAlerts} dismissible > <p>{message}</p> </Alert> ); }
另外,父组件的Table组件里还漏了导入useState,需要补上:
// 在Table组件顶部添加 import { useState } from "react";
内容的提问来源于stack exchange,提问作者viking

