不变违规:对象作为React子对象无效

问题描述 投票:252回答:31

在我的组件的渲染功能中,我有:

render() {
    const items = ['EN', 'IT', 'FR', 'GR', 'RU'].map((item) => {
      return (<li onClick={this.onItemClick.bind(this, item)} key={item}>{item}</li>);
    });
    return (
      <div>
        ...
                <ul>
                  {items}
                </ul>
         ...
      </div>
    );
  }

一切都很好,但是当点击<li>元素时,我收到以下错误:

未捕获错误:不变违规:对象无效作为React子对象(找到:具有键的对象{dispatchConfig,dispatchMarker,nativeEvent,target,currentTarget,type,eventPhase,bubbles,cancelable,timeStamp,defaultPrevented,isTrusted,view,detail,screenX ,screenY,clientX,clientY,ctrlKey,shiftKey,altKey,metaKey,getModifierState,button,buttons,relatedTarget,pageX,pageY,isDefaultPrevented,isPropagationStopped,_dispatchListeners,_dispatchIDs})。如果您要渲染子集合,请使用数组,或使用React附加组件中的createFragment(object)包装对象。检查Welcome的渲染方法。

如果我在地图函数中更改为this.onItemClick.bind(this, item)(e) => onItemClick(e, item),一切都按预期工作。

如果有人能解释我做错了什么并解释为什么我会收到这个错误,那就太好了

更新1: onItemClick函数如下,删除this.setState导致错误消失。

onItemClick(e, item) {
    this.setState({
      lang: item,
    });
}

但我无法删除此行,因为我需要更新此组件的状态

javascript reactjs
31个回答
328
投票

我遇到了这个错误,结果是我无意中在我的JSX代码中包含了一个我希望是字符串值的Object:

return (
    <BreadcrumbItem href={routeString}>
        {breadcrumbElement}
    </BreadcrumbItem>
)

breadcrumbElement曾经是一个字符串,但由于重构已成为一个对象。不幸的是,React的错误信息并没有很好地指出我存在问题的那一行。我必须一直跟踪我的堆栈跟踪,直到我认识到传递给组件的“props”,然后我找到了有问题的代码。

您需要引用作为字符串值的对象的属性,或者将Object转换为所需的字符串表示形式。如果你真的想看到对象的内容,一个选项可能是JSON.stringify


4
投票

我也有同样的问题,但我的错误是如此愚蠢。我试图直接访问对象。

class App extends Component {
    state = {
        name:'xyz',
        age:10
    }
    render() {
        return (
            <div className="App">
                // this is what I am using which gives the error
                <p>I am inside the {state}.</p> 

                //Correct Way is

                <p>I am inside the {this.state.name}.</p> 
            </div>
        );
    }                                                                             

}

2
投票

你只是使用对象的键,而不是整个对象!

更多细节可以在这里找到:https://github.com/gildata/RAIO/issues/48

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class SCT extends Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            data: this.props.data,
            new_data: {}
        };
    }
    componentDidMount() {
        let new_data = this.state.data;
        console.log(`new_data`, new_data);
        this.setState(
            {
                new_data: Object.assign({}, new_data)
            }
        )
    }
    render() {
        return (
            <div>
                this.state.data = {JSON.stringify(this.state.data)}
                <hr/>
                <div style={{color: 'red'}}>
                    {this.state.new_data.name}<br />
                    {this.state.new_data.description}<br />
                    {this.state.new_data.dependtables}<br />
                </div>
            </div>
        );
    }
}

SCT.propTypes = {
    test: PropTypes.string,
    data: PropTypes.object.isRequired
};

export {SCT};
export default SCT;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

2
投票

这样的事情刚刚发生在我身上......

我写:

{response.isDisplayOptions &&
{element}
}

将它放在div中固定它:

{response.isDisplayOptions &&
    <div>
        {element}
    </div>
}

2
投票

在我的情况下,我忘了从渲染功能返回一个html元素,我正在返回一个对象。我做的是我只是用{html元素包裹{items} - 一个像下面这样的简单div

<ul>{items}</ul>

1
投票

我想在此列表中添加另一个解决方案。

眼镜:

  • “反应”:“^ 16.2.0”,
  • “react-dom”:“^ 16.2.0”,
  • “react-redux”:“^ 5.0.6”,
  • “react-scripts”:“^ 1.0.17”,
  • “redux”:“^ 3.7.2”

我遇到了同样的错误:

未捕获错误:对象无效作为React子对象(找到:具有键{XXXXX}的对象)。如果您要渲染子集合,请使用数组。

这是我的代码:

let payload = {
      guess: this.userInput.value
};

this.props.dispatch(checkAnswer(payload));

解:

  // let payload = {
  //   guess: this.userInput.value
  // };

this.props.dispatch(checkAnswer(this.userInput.value));

问题出现了,因为有效负载正在将项目作为对象发送。当我删除有效负载变量并将userInput值放入分派时,一切都按预期开始工作。


1
投票

如果您使用Firebase项目中的任何文件。然后在最后放置导入firebase语句!!

我知道这听起来很疯狂,但试试看!!


1
投票

我有同样的问题,在我的情况下,我更新redux状态,并且新数据参数与旧参数不匹配,所以当我想通过此错误访问某些参数时,

也许这种经历有助于某人


1
投票

当我遇到以下错误时,我的问题很简单:

objects are not valid as a react child (found object with keys {...}

只是因为我正在尝试使用{object}直接在组件中渲染对象时使用错误中指定的键传递一个对象,期望它是一个字符串

object: {
    key1: "key1",
    key2: "key2"
}

在React Component上渲染时,我使用了类似下面的内容

render() {
    return this.props.object;
}

但应该是

render() {
    return this.props.object.key1;
}

1
投票

如果使用无状态组件,请遵循以下格式:

const Header = ({pageTitle}) => (
  <h1>{pageTitle}</h1>
);
export {Header};

这似乎对我有用


1
投票

如果您使用的是Firebase并看到此错误,那么检查您是否正确导入它是值得的。从版本5.0.4开始,您必须像这样导入它:

import firebase from '@firebase/app'
import '@firebase/auth';
import '@firebase/database';
import '@firebase/storage';

是的我知道。我也失去了45分钟。


86
投票

因此,在尝试显示作为Date对象的createdAt属性时出现此错误。如果你像这样连接.toString(),它将进行转换并消除错误。只是将其作为可能的答案发布,以防其他人遇到同样的问题:

{this.props.task.createdAt.toString()}

1
投票

我也得到这个“对象无效作为React子”错误,对我来说原因是由于在我的JSX中调用异步函数。见下文。

class App extends React.Component {
    showHello = async () => {
        const response = await someAPI.get("/api/endpoint");

        // Even with response ignored in JSX below, this JSX is not immediately returned, 
        // causing "Objects are not valid as a React child" error.
        return (<div>Hello!</div>);
    }

    render() {
        return (
            <div>
                {this.showHello()}
            </div>
        );
    }
}

我学到的是React不支持异步渲染。 React团队正在研究here记录的解决方案。


0
投票

我只是通过一个非常愚蠢的错误版本,我也可以在这里分享后代。

我有一些像这样的JSX:

...
{
  ...
  <Foo />
  ...
}
...

我需要对此进行评论以调试某些内容。我在IDE中使用了键盘快捷键,结果如下:

...
{
  ...
  { /* <Foo /> */ }
  ...
}
...

当然,这是无效的 - 对象作为反应孩子无效!


0
投票

如果使用Firebase,如果它不能通过放在import语句的末尾,那么你可以尝试将其置于生命周期方法之一,也就是说,你可以将它放在componentWillMount()中。

componentWillMount() {
    const firebase = require('firebase');
    firebase.initializeApp({
        //Credentials
    });
}

0
投票

当使用需要Invariant Violation: Objects are not valid as a React child道具的组件时,renderItem发生在我身上,例如:

renderItem={this.renderItem}

而我的错误是让我的renderItem方法async


0
投票

我的错误是因为这样写:

props.allinfo.map((stuff, i)=>{
  return (<p key={i}> I am {stuff} </p>)
})

代替:

props.allinfo.map((stuff, i)=>{
  return (<p key={i}> I am {stuff.name} </p>)
})

这意味着我试图渲染对象而不是其中的值。

编辑:这是为了反应不是原生的。


0
投票

我的问题非常特别:在我的.env文件中,我在有我的api url的行中添加了注释:

API_URL=https://6ec1259f.ngrok.io #comment

当我尝试登录/注册时,我会收到Invariant violation错误,因为api url是错误的。


0
投票
try{
    throw new Error(<p>An error occured</p>)
}catch(e){
    return (e)
}

上面的代码产生了错误,然后我重写了这样:

try{
    throw(<p>An error occured</p>)
}catch(e){
    return (e)
}

注意在try块中删除新的Error()...

编写代码以避免此错误消息的更好方法期望抛出的对象no-throw-literal是将字符串传递给throw new Error()而不是JSX并在catch块中返回JSX,类似这样的:

try{
    throw new Error("An error occurred")
}catch(e){
    return (
        <p>{e.message}</p>
    )
}

0
投票
  1. 发生了什么是你试图实现的onClick函数立即执行。
  2. 由于我们的代码不是HTML,因此它是javascript,因此它被解释为函数执行。
  3. onClick函数将函数作为参数而不是函数执行。

const items = ['EN', 'IT', 'FR', 'GR', 'RU'].map((item) => { return (<li onClick={(e) => onItemClick(e, item)} key={item}>{item}</li>); });

这将在List Item上定义一个onClick函数,该函数将在我们的组件呈现后立即单击它来执行。


0
投票

显然,正如其他人之前在这个帖子中提到的,在React JSX中,props.children cannot be of type Object。这不是您特定问题中问题的根本原因。

如果您仔细阅读错误文本,您将看到React在尝试呈现与SyntheticEvent的签名匹配的Object时产生错误:

Uncaught Error: Invariant Violation: Objects are not valid as a React child (found: object with keys {dispatchConfig, dispatchMarker, nativeEvent, target, currentTarget, type, eventPhase, bubbles, cancelable, timeStamp, defaultPrevented, isTrusted, view, detail, screenX, screenY, clientX, clientY, ctrlKey, shiftKey, altKey, metaKey, getModifierState, button, buttons, relatedTarget, pageX, pageY, isDefaultPrevented, isPropagationStopped, _dispatchListeners, _dispatchIDs}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of Welcome.

但是,有人想知道你为什么要渲染一个SyntheticEvent,这就是你问题的真正答案所在。你显然无意渲染SyntheticEvent,但是你的事件处理程序参数没有乱序。

在你的render方法中,你将onItemClick事件处理程序绑定到类组件的this并传入item作为参数:

render() {
    const items = ['EN', 'IT', 'FR', 'GR', 'RU'].map((item) => {
      return (<li onClick={this.onItemClick.bind(this, item)} key={item}>{item}</li>);
    });
// ...

根据Function.prototype.bind的文档,在thisArg之后传递的所有参数都被添加到随后在稍后调用目标函数时传递的任何参数:

arg1,arg2,...

在调用目标函数时预先添加到绑定函数的参数的参数。

如果我们再查看事件处理程序,我们会看到参数e在参数item之前列出。

onItemClick(e, item) {
    this.setState({
      lang: item,
    });
}

当调用onItemClick(e, item)时,在item调用期间传入的bind将在触发event之前,因此参数e将被设置为映射和绑定的item,参数item将被设置为event

setState被调用时,lang将被设置为代表触发SyntheticEvent事件的onClick,当你尝试在this.state.lang其他地方渲染值时,你将收到你见过的不变违规错误。


0
投票

找到:带键的对象

这意味着你传递的东西是一个键值,所以你需要修改你的处理程序。

onItemClick(e, item) {
   this.setState({
     lang: item,
   });
}

onItemClick({e, item}) {
   this.setState({
     lang: item,
   });
}

你错过了大括号({})。


28
投票

我只是得到了相同的错误,但由于一个不同的错误:我使用双括号,如:

{{count}}

插入count的值而不是正确的:

{count}

编译器可能会变成{{count: count}},即尝试插入一个Object作为React子。


0
投票

只需创建一个有效的JSX元素。在我的例子中,我为一个对象分配了一个组件。

const AwesomeButtonComponent = () => <button>AwesomeButton</button>
const next = {
  link: "http://awesomeLink.com",
  text: "Awesome text",
  comp: AwesomeButtonComponent
}

我的代码中的其他地方我想动态分配该按钮。

return (
  <div>
    {next.comp ? next.comp : <DefaultAwesomeButtonComp/>}
  </div>
)

我通过声明一个我通过props comp初始化的JSX comp来解决这个问题。

const AwesomeBtnFromProps = next.comp
return (
  <div>
    {next.comp ? <AwesomeBtnFromProps/> : <DefaultAwesomeButtonComp/>}
  </div>
)

24
投票

只是想我会添加到这个,因为我今天遇到了同样的问题,结果是因为我只是返回函数,当我将它包装在<div>标签中时它开始工作,如下所示

renderGallery() {
  const gallerySection = galleries.map((gallery, i) => {
    return (
      <div>
        ...
      </div>
    );
  });
  return (
    {gallerySection}
  );
}

以上导致了错误。我通过将return()部分更改为:

return (
  <div>
    {gallerySection}
  </div>
);

......或者干脆:

return gallerySection

12
投票

我不得不在不必要的情况下将花括号放在一个变量中,该变量在render()函数的return语句中包含一个HTML元素。这使得React将其视为对象而非元素。

render() {
  let element = (
    <div className="some-class">
      <span>Some text</span>
    </div>
  );

  return (
    {element}
  )
}

一旦我从元素中删除花括号,错误就消失了,元素被正确呈现。


9
投票

我不得不忘记发送到演示组件的道具周围的花括号:

之前:

const TypeAheadInput = (name, options, onChange, value, error) => {

const TypeAheadInput = ({name, options, onChange, value, error}) => {

7
投票

对于任何使用Android版Firebase的人来说,这只能打破Android。我的iOS模拟忽略了它。

并由Apoorv Bankey发布。

Firebase V5.0.3以上的任何东西,对于Android,atm都是一个破产。固定:

npm i --save [email protected]

在这里确认无数次https://github.com/firebase/firebase-js-sdk/issues/871


7
投票

React child(singular)应该是primitive数据类型而不是对象的类型,或者它可能是JSX标记(在我们的例子中不是这样)。在开发中使用Proptypes包以确保验证发生。

只需一个快速的代码片段(JSX)比较来代表您的想法:

  1. 错误:将对象传递给子级 <div> {/* item is object with user's name and its other details on it */} {items.map((item, index) => { return <div key={index}> --item object is passed which is error--->>>{item}</div>; })} </div>
  2. 没有错误:将对象的属性(应该是原始的,即字符串值或整数值)传递给子级。 <div> {/* item is object with user's name and its other details on it */} {items.map((item, index) => { return <div key={index}> --note the name property is primitive--->{item.name}</div>; })} </div>

TLDR; (从下面的源代码):确保在JSX中渲染的所有项目都是基元,而不是使用React时的对象。发生此错误通常是因为调度事件涉及的函数被赋予了意外的对象类型(即,当您应该传递字符串时传递对象)或组件中的部分JSX没有引用基元(即this.props) vs this.props.name)。

来源 - codingbismuth.com


4
投票

如果由于某种原因你导入了firebase。然后尝试运行npm i --save [email protected]。这是因为firebase break本身反应,所以运行它会修复它。

© www.soinside.com 2019 - 2024. All rights reserved.