React中'type is invalid'错误排查求助
type is invalid问题 错误信息
type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
附带调用栈提示:
Check the render method of 'MoviesCouch'at createAndFibersFromTypeProps, createFiberFromElement, reconcileSingleElement, reconcileChildFibers, reconcileChild, updateHostComponent, beginWork , HTMLUnknownElement.callCallback, Object.invokeGuardedCallbackDev, nvokeGuardedCallback, beginWork$1, performUnitOfWork, workLoopSync, at renderRootSync, at performConcurrentWorkOnRoot, at workLoop , at flushWork , at MessagePort.performWorkUntilDeadline or this message Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
相关代码
import {React, useEffect, useState} from "react"; import { Col, Row} from "react-bootstrap"; import { Container } from "react-bootstrap"; import { toast } from "react-bootstrap"; import PropTypes from "prop-types"; import FavoriteMovies from "./favorite-movies"; import UserInfo from "./user-info"; import UpdateView from "./update-user"; import DeleteUser from "./delete-user"; export const TestProfile= ({user, setUser, movies, token, updateUser}) => { const [myUser, setMyUser] = useState(""); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [email, setEmail] = useState(""); const [birthday, setBirthday] = useState(""); //get users useEffect(() => { const token = window.localStorage.getItem("token"); fetch(`https://movies-couch-api.vercel.app/users/${user.Username}`, { method: "GET", headers: { Authorization: `Bearer ${token}` } }) .then((response) => { if (response.ok) { console.log("User data retrieved") } else { console.log("User data coudl not be retrieved.") } setMyUser(response.data); console.log(response); }) .catch((error) => { console.error("An error ocurred" + error); }); }, []); // let moviesId = movies_.id -> ? // Fav-movies // const favoriteMovies = movies.filter((movie) => favoriteMovies.includes(movie._id)) // remove-fav_Movies removeFavMovie = async (movies) => { const user = localStorage.getItem("user"); console.log(user); const token = localStorage.getItem("token"); console.log(token); fetch(`https://movies-couch-api.vercel.app/users/${user.Username}/movies/${movies._id}`, { method: "DELETE", header: {Authorization: `Bearer ${token}`}} ) .then((response) => { console.log(response); toast.success(`The Movie: ${movies._id} was removed from Favorite List`) }) .catch(function (error) { console.error(" An error ocurred" +error); }) } console.log(useEffect); console.log(updateUser); return ( <Container className="profile-view"> <Row className="d-flex justify-content-center p-4"> <Col > <UserInfo user={user}/> </Col> </Row> <Row className="d-flex justify-content-center p-4"> <Col > <UpdateView user={user} updateUser={updateUser}/> </Col> </Row> <Row> <Col> <FavoriteMovies /> </Col> </Row> <Row className="d-flex justify-content-center p-4"> <Col> <DeleteUser user={user}/> </Col> </Row> </Container> ); }; TestProfile.propTypes = { user: PropTypes.object, movies: PropTypes.object, token: PropTypes.number, updateUser: PropTypes.func, removeFavMovie: PropTypes.func }
错误原因分析
子组件导入导出不匹配:错误提示明确指向组件导入/导出问题。当前代码使用默认导入(如
import UserInfo from "./user-info"),但如果对应的子组件是命名导出(如export const UserInfo = () => {}),会导致导入的组件为undefined,最终触发渲染错误。react-bootstrap toast 导入错误:react-bootstrap 中没有名为
toast的函数导出,你使用的toast.success是react-toastify库的API,当前导入会导致toast为undefined,虽不是直接触发组件类型错误,但会引发后续执行错误。函数组件内方法定义语法错误:
removeFavMovie = async (movies) => {}是类组件的方法定义语法,在函数组件中必须使用const声明变量来定义函数,否则会引发语法错误,导致组件无法正常渲染。useEffect 闭包与数据处理问题:
useEffect依赖数组为空,但内部使用了user.Username,会导致闭包引用旧值;同时fetch返回的response未调用.json()就直接取response.data,无法正确获取接口数据。
解决方法
1. 统一子组件导入导出方式
检查每个子组件(FavoriteMovies、UserInfo、UpdateView、DeleteUser)的导出方式:
- 如果子组件是默认导出(
export default UserInfo),保持当前导入方式不变; - 如果子组件是命名导出(
export const UserInfo = () => {}),修改导入语句为命名导入:import { UserInfo } from "./user-info"; import { UpdateView } from "./update-user"; // 其他子组件同理
2. 修复 toast 使用问题
如果需要函数式提示,改用react-toastify库:
- 安装依赖:
npm install react-toastify - 导入并配置:
import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; // 在组件返回的JSX末尾添加ToastContainer return ( <Container className="profile-view"> {/* 其他组件 */} <ToastContainer /> </Container> )
3. 修正函数组件内方法定义
将removeFavMovie改为函数组件合法的定义方式:
const removeFavMovie = async (movies) => { const user = JSON.parse(localStorage.getItem("user")); // localStorage存的是字符串,需解析为对象 console.log(user); const token = localStorage.getItem("token"); console.log(token); fetch(`https://movies-couch-api.vercel.app/users/${user.Username}/movies/${movies._id}`, { method: "DELETE", headers: {Authorization: `Bearer ${token}`} // 修正拼写:header -> headers }) .then((response) => { console.log(response); toast.success(`The Movie: ${movies._id} was removed from Favorite List`) }) .catch(function (error) { console.error(" An error occurred" + error); }) }
4. 修复 useEffect 逻辑
useEffect(() => { const token = window.localStorage.getItem("token"); fetch(`https://movies-couch-api.vercel.app/users/${user.Username}`, { method: "GET", headers: { Authorization: `Bearer ${token}` } }) .then((response) => { if (response.ok) { console.log("User data retrieved") return response.json(); // 解析response为JSON格式 } else { console.log("User data could not be retrieved.") throw new Error('Failed to fetch user data'); } }) .then(data => { setMyUser(data); // 使用解析后的数据更新状态 console.log(data); }) .catch((error) => { console.error("An error occurred: " + error); }); }, [user.Username]); // 添加依赖,避免闭包导致的旧值问题
内容的提问来源于stack exchange,提问作者Hermann Rasch

