React使用this.state渲染组件时出现元素类型无效报错
React Invalid Element Type 报错修复方案
控制台报错信息
- 警告:
React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: array,提示检查ButtonMenu.js第432行代码 - 错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object
问题根因
报错由命名混淆直接触发,附带1个逻辑bug:
- 代码中定义的
ProductList是存储产品条目的普通JavaScript数组,并非React组件,但render方法中直接以JSX标签形式书写了<ProductList products={this.state.products} /> - JSX解析规则明确要求:大写开头的标签会被识别为自定义组件,对应值必须是函数/类形式的合法组件定义;小写开头的标签会被识别为原生HTML标签,对应值必须是字符串类型的标签名。此处传入数组类型,完全不符合类型要求,直接抛出类型无效错误。
- 现有分类过滤逻辑未处理
All选项,点击全部分类时会匹配不到任何数据,返回空数组导致列表空白。
修复方案
按以下步骤调整代码即可解决问题:
- 将存储原始产品数据的数组重命名为
PRODUCT_DATA,和组件名做明确区分,常量使用全大写命名也符合通用编码规范 - 定义合法的
ProductList函数组件,接收products属性,遍历传入的产品数组渲染列表UI - 修正分类过滤逻辑,点击「All」选项时直接返回全量产品数据,其余分类按category字段做匹配过滤
修复后的完整代码如下:
import React, {Component} from "react"; // 重命名原产品数据数组,与组件名做区分 const PRODUCT_DATA = [ { id:0, category:"accessories", image:"./prod_images/accessory1.jpg", product: "product1", description: "product1", price: 0.00 }, // 此处保留原有50+个产品对象即可 ]; const CATEGORIES = ['All', 'Men', 'Women', 'Jerseys', 'Shirts', 'Accessories', 'Collectables']; // 定义合法的ProductList组件 const ProductList = (props) => { const { products } = props; return ( <div className="product-list-wrap"> {products.map(productItem => ( <div key={productItem.id} className="product-card"> <img src={productItem.image} alt={productItem.product} /> <h4>{productItem.product}</h4> <p>{productItem.description}</p> <p className="price">${productItem.price.toFixed(2)}</p> </div> ))} </div> ) } class ButtonMenu extends Component { constructor(props) { super(props); this.state = { products: PRODUCT_DATA }; } getCategory = category => { // 处理全部分类的逻辑 if (category === 'all') { this.setState({products: PRODUCT_DATA}); return; } const filteredList = PRODUCT_DATA.filter(item => item.category.toLowerCase() === category); this.setState({products: filteredList}); }; render() { return ( <> <div className="button Menu-container"> <ProductList products={this.state.products} /> {CATEGORIES.map(item => ( <button key ={item.toString()} className="main-btn" onClick={() => this.getCategory(item.toLowerCase())} value={item.toLowerCase()}> {item} </button> ))} </div> </> ); } } export default ButtonMenu;
注意:编写JSX时需要严格区分普通数据变量和组件变量,所有作为标签使用的大写开头变量,必须是合法的React组件定义,禁止将数组、普通对象、字符串等非组件类型作为JSX标签使用。
内容的提问来源于stack exchange,提问作者madQuestions
相关产品推荐
相关产品推荐

