自定义Snackbar组件使用children属性时报错,寻求解决办法
Snackbar组件显示错误排查与解决
问题概述
开发的用于数据添加成功通知的Snackbar组件无法正常显示,出现以下三类错误:
Warning: Failed prop type: Invalid prop 'children' supplied to 'ForwardRef(Alert)', expected a ReactNodeError: Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.console.js:288 The above error occurred in the <div> component:
已尝试设置默认消息但无效,怀疑是后端返回数据或组件使用位置导致问题,组件代码如下:
import React, { createContext, useContext, useState, forwardRef } from "react"; import Snackbar from "@mui/material/Snackbar"; import MuiAlert from "@mui/material/Alert"; const Alert = forwardRef(function Alert(props, ref) { return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />; }); const SnackbarContext = createContext(); export const useSnackbar = () => { return useContext(SnackbarContext); }; const SnackbarProvider = ({ children }) => { const [snackbar, setSnackbar] = useState({ open: false, message: "", severity: "info", }); const showSnackbar = (message = "", severity = "info") => { setSnackbar({ open: true, message: message || "No message", severity }); }; const handleClose = (event, reason) => { if (reason === "clickaway") { return; } setSnackbar({ ...snackbar, open: false }); }; return ( <SnackbarContext.Provider value={showSnackbar}> {children} {snackbar.open && snackbar.message && ( <Snackbar open={snackbar.open} autoHideDuration={6000} onClose={handleClose} anchorOrigin={{ vertical: "top", horizontal: "center" }} > <Alert onClose={handleClose} severity={snackbar.severity} sx={{ width: "100%" }} > {snackbar.message} </Alert> </Snackbar> )} </SnackbarContext.Provider> ); }; export default SnackbarProvider;
错误原因分析
核心问题是**snackbar.message被设置为了对象而非字符串**:
- 当调用
showSnackbar时,如果传入的是后端返回的空对象(比如接口返回{}),或者误传了整个响应对象而非具体的消息字符串,就会导致React无法渲染对象类型的子元素,触发"Objects are not valid as a React child"错误。 - 第一个警告是Alert组件期望接收合法的ReactNode(字符串属于合法类型,对象不属于),本质也是message类型错误导致的。
解决方案
1. 严格校验并转换message类型
修改showSnackbar函数,确保最终存入state的message是字符串:
const showSnackbar = (message = "", severity = "info") => { let displayMessage = "No message"; // 优先处理字符串类型 if (typeof message === 'string' && message.trim()) { displayMessage = message; } // 如果是对象,尝试提取内部的message字段(适配后端返回格式) else if (typeof message === 'object' && message !== null) { displayMessage = message.message || "操作完成"; } setSnackbar({ open: true, message: displayMessage, severity }); };
2. 渲染层添加兜底处理
在Alert组件内部添加类型判断,确保渲染的是合法内容:
<Alert onClose={handleClose} severity={snackbar.severity} sx={{ width: "100%" }} > {typeof snackbar.message === 'string' ? snackbar.message : "操作提示"} </Alert>
3. 检查调用场景
确认调用useSnackbar()的地方,是否正确传入了字符串:
- 如果是后端接口返回,确保取的是响应中的消息字段(比如
response.data.message而非response.data); - 避免直接传入空对象、undefined等非字符串类型的值。
修改后的完整代码
import React, { createContext, useContext, useState, forwardRef } from "react"; import Snackbar from "@mui/material/Snackbar"; import MuiAlert from "@mui/material/Alert"; const Alert = forwardRef(function Alert(props, ref) { return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />; }); const SnackbarContext = createContext(); export const useSnackbar = () => { return useContext(SnackbarContext); }; const SnackbarProvider = ({ children }) => { const [snackbar, setSnackbar] = useState({ open: false, message: "", severity: "info", }); const showSnackbar = (message = "", severity = "info") => { let displayMessage = "No message"; if (typeof message === 'string' && message.trim()) { displayMessage = message; } else if (typeof message === 'object' && message !== null) { displayMessage = message.message || "操作完成"; } setSnackbar({ open: true, message: displayMessage, severity }); }; const handleClose = (event, reason) => { if (reason === "clickaway") { return; } setSnackbar({ ...snackbar, open: false }); }; return ( <SnackbarContext.Provider value={showSnackbar}> {children} {snackbar.open && ( <Snackbar open={snackbar.open} autoHideDuration={6000} onClose={handleClose} anchorOrigin={{ vertical: "top", horizontal: "center" }} > <Alert onClose={handleClose} severity={snackbar.severity} sx={{ width: "100%" }} > {typeof snackbar.message === 'string' ? snackbar.message : "操作提示"} </Alert> </Snackbar> )} </SnackbarContext.Provider> ); }; export default SnackbarProvider;
内容的提问来源于stack exchange,提问作者Rafi rizqullah ramadhan
相关产品推荐
相关产品推荐

