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

在我组件的渲染函数中,我有:

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>元素时,我收到以下错误:

Uncaught Error: Invariant Violation:对象作为React无效 child(发现:对象的键{dispatchConfig, dispatchMarker, nativeEvent,目标,currentarget,类型,eventPhase,气泡, 可取消的,时间戳,defaultblocked, isTrusted,视图,详细信息, screenX, screenY, clientX, clienti, ctrlKey, shiftKey, altKey, metaKey, getModifierState,按钮,按钮,relatedTarget, pageX, pageY, isdefaultblocked, isPropagationStopped, _dispatchListeners, _dispatchIDs})。如果你打算呈现一个子集合,使用数组代替,或者使用createFragment(object) from包装对象 React插件。检查Welcome的渲染方法

如果我在映射函数中将this.onItemClick.bind(this, item)改为(e) => onItemClick(e, item),一切都能正常工作。

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

更新1:< p > < br > onItemClick函数如下所示。

. setState导致错误消失
onItemClick(e, item) {
this.setState({
lang: item,
});
}

但是我不能删除这一行,因为我需要更新这个组件的状态

829828 次浏览

感谢zerkms的评论,我能够注意到我的愚蠢错误:

我有onItemClick(e, item)时,我应该有onItemClick(item, e)

我有这个错误,原来是我无意中包括一个对象在我的JSX代码,我本以为是一个字符串值:

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

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

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

所以当我试图显示Date对象的createdAt属性时,我得到了这个错误。如果你像这样将.toString()连接到末尾,它会进行转换并消除错误。只是把这个作为一个可能的答案,以防其他人遇到同样的问题:

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

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

\{\{count}}

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

{count}

编译器可能会将其转换为\{\{count: count}},即试图将一个对象作为React子对象插入。

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

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

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

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

...或者仅仅是:

return gallerySection

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

更多细节可以在这里找到: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>

我的问题是忘记了道具周围的花括号被发送到一个表示组件:

之前:

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

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

我只是让自己经历了一个非常愚蠢的错误版本,我不妨在这里为后代分享一下。

我有一些JSX是这样的:

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

我需要注释掉它来调试一些东西。我在IDE中使用键盘快捷键,结果是这样的:

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

当然,这是无效的——对象作为react子对象是无效的!

我的问题是,在render()函数的return语句中,不必要地在一个包含HTML元素的变量周围加上花括号。这使得React将其视为对象而不是元素。

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


return (
{element}
)
}

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

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

规格:

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

我也遇到了同样的错误:

Uncaught Error:对象作为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值放入分派时,一切都开始正常工作。

如果你在项目中使用Firebase的任何文件。 然后把import firebase语句放在最后!!< / p >

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

如果出于某种原因你导入了firebase。然后尝试运行npm i --save firebase@5.0.3。这是因为firebase破坏反应本机,所以运行这个将修复它。

对于任何在Android上使用Firebase的人来说,这只会破坏Android。我的iOS模拟忽略了它。

如上Apoorv Bankey所述。

对于Android来说,任何Firebase V5.0.3以上的东西都是失败的。解决办法:

npm i --save firebase@5.0.3

这里已经确认了很多次 https://github.com/firebase/firebase-js-sdk/issues/871 < / p >

在使用Firebase的情况下,如果在import语句的末尾放置它不起作用,那么你可以尝试将它放在一个生命周期方法中,也就是说,你可以将它放在componentWillMount()中。

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

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

renderItem={this.renderItem}

我的错误是使我的renderItem方法async

我的错误是这样写的:

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

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

编辑:这是反应不是本机。

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

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

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

在我的情况下,我有同样的问题, 我更新了回来的状态,新的数据参数与旧的参数不匹配,所以当我想通过这个错误访问一些参数时,

也许这种经历能帮助到某些人

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

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>
);
}


}

我的问题很简单,当我面对以下错误:

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

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

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

当在React组件上渲染时,我使用了如下所示的东西

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

但它本该如此

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

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

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

这似乎对我很管用

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块中新的错误()的删除…

为了避免这种错误消息期望抛出一个对象为no-throw-literal,编写代码的更好方法是将一个字符串传递给抛出新的错误()而不是JSX,并在catch块中返回JSX,如下所示:

try{
throw new Error("An error occurred")
}catch(e){
return (
<p>{e.message}</p>
)
}
  1. 所发生的是您试图实现的onClick函数立即被执行。

  2. 因为我们的代码不是HTML,它是javascript,所以它被解释为一个函数执行。

  3. onClick函数接受函数作为参数,而不是函数执行。

< p > <代码> const项=[“EN”,“它”,“FR”,“格”,“俄罗斯”). map((项)=比;{ return (<li onClick={(e) =>onItemClick (e,项)}关键={项}在{项}& lt; / li>); }); < /代码> < / p >

这将在List Item上定义一个onClick函数,该函数将在单击它后执行,而不是在组件呈现时立即执行。

类似的事情刚刚发生在我身上……

我写:

{response.isDisplayOptions &&
{element}
}

把它放在一个div固定:

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

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

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

是的,我知道。我在这上面也浪费了45分钟。

在我的情况下,它是我忘记从渲染函数返回html元素,我返回一个对象。我所做的是我只是包装了一个html元素的{items} -一个简单的div像下面

<ul>{items}</ul>

显然,正如其他人之前在这个线程中提到的,在React JSX props.children 不能为Object类型中。这不是根本原因的问题在你的具体问题。

如果你仔细阅读错误文本,你会发现React在试图呈现一个匹配SyntheticEvent签名的对象时产生了错误:

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.bindthisArg之后传递的所有参数都是前置到后来调用目标函数时传递的任何参数的文档:

Arg1, arg2,…

参数提供的参数前的参数 调用目标函数时绑定的函数

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

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

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

setState被调用时,lang将被设置为表示触发onClick事件的SyntheticEvent,当你试图在其他地方呈现this.state.lang中的值时,你将收到你所看到的不变违反错误。

Found:带有键的对象

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

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

你漏掉了括号({})。

我也得到了这个“对象是无效的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团队正在研究解决方案如下所示

只需创建一个有效的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>
)

我在三元运算符中得到了这个错误。 我所做的:

render(){
const bar = <div>asdfasdf</div>
return ({this.state.foo ? {bar} : <div>blahblah</div>})
}

结果是它应该是没有括号的bar,比如:

render(){
const bar = <div>asdfasdf</div>
return ({this.state.foo ? bar : <div>blahblah</div>})
}

对于那些提到Stringify()toString()作为解决方案的人,我会说这对我有用,但我们必须理解问题以及为什么会发生。在我的代码中,这是一个简单的问题。我有两个调用相同函数的按钮,但其中一个按钮没有正确地将参数传递给该函数

在我的例子中,这是因为必须在运行时注入动态数组。

我只是为对象添加了空检查,它工作得很好。

之前:

...
render(
...
<div> {props.data.roles[0]} </div>
...
);

后:

...
let items = (props && props.data && props.data.roles)? props.data.roles: [];
render(
...
<div> {items[i]} </div>
...
);

我也有同样的问题,因为我没有把props放在花括号里。

export default function Hero(children, hero ) {
return (
<header className={hero}>
{children}
</header>
);
}
所以如果你的代码与上面的类似,那么你会得到这个错误。 要解决这个问题,只需在props.

export default function Hero({ children, hero }) {
return (
<header className={hero}>
{children}
</header>
);
}

我得到了同样的错误,我改变了这个

export default withAlert(Alerts)

这个

export default withAlert()(Alerts)

在旧版本中,前一个代码是可以的,但在后来的版本中,它抛出一个错误。所以使用后面的代码来避免错误。

在我的例子中,我向我的子函数组件添加了一个async,并遇到了这个错误。不要使用带有子组件的async。

通常这是因为你没有正确地解构。以下面的代码为例:

const Button = text => <button>{text}</button>


const SomeForm = () => (
<Button text="Save" />
)

我们用= text =>参数来声明它。但实际上,React期望它是一个包涵一切的props对象。

所以我们真的应该这样做:

const Button = props => <button>{props.text}</button>


const SomeForm = () => (
<Button text="Save" />
)

注意到区别了吗?这里的props参数可以被命名为任何东西(props只是与命名法相匹配的约定),React只是期望一个具有键和val的对象。

使用对象解构你可以做,并且经常会看到类似这样的事情:

const Button = ({ text }) => <button>{text}</button>


const SomeForm = () => (
<Button text="Save" />
)

...这工作。

有可能,任何偶然发现这一点的人只是不小心声明了他们组件的props参数而没有解构。

只需删除return语句中的花括号。

之前:

render() {
var rows = this.props.products.map(product => <tr key={product.id}><td>{product.name}</td><td>{product.price}</td></tr>);
return {rows}; // unnecessary
}

后:

render() {
var rows = this.props.products.map(product => <tr key={product.id}><td>{product.name}</td><td>{product.price}</td></tr>);
return rows; // add this
}

试试这个

 {items && items.title ? items.title : 'No item'}

我得到这个错误每当我在我的FlatList的renderItem函数上调用async。

在调用FlatList中的状态数据之前,我必须创建一个新函数来将我的Firestore集合设置为我的状态。

这是我的代码:

class App extends Component {
constructor(props){
super(props)
this.state = {
value: null,
getDatacall : null
}
this.getData = this.getData.bind(this)
}
getData() {
//   if (this.state.getDatacall === false) {
sleep(4000)
returnData("what is the time").then(value => this.setState({value, getDatacall:true}))
// }
}
componentDidMount() {
sleep(4000)


this.getData()
}
render() {
this.getData()
sleep(4000)
console.log(this.state.value)
return (
<p> { this.state.value } </p>
)
}
}

我就遇到了这个错误。我不得不把它改成

 render() {
this.getData()
sleep(4000)
console.log(this.state.value)
return (
<p> { JSON.stringify(this.state.value) } </p>
)
}

希望这能帮助到一些人!

我的案例在使用reduce时很常见,但这里没有分享,所以我发布了它。

通常,如果你的数组是这样的:

[{ value: 1}, {value: 2}]

你想在这个数组中呈现value的和。JSX代码如下所示

<div>{array.reduce((acc, curr) => acc.value + curr.value)}</div>
当你的数组只有一个项时,问题会发生,例如:[{value: 1}]。 (通常,当你的数组是来自服务器的响应时,这种情况发生,所以你不能保证数组中有多少项)

当数组只有一个元素时,reduce函数返回元素本身,在这种情况下它是{value: 1}(一个对象),它会导致不变性违反:对象作为React子对象无效错误。

只需删除组件中的async关键字。

const Register = () => {

这之后就没有问题了。

由于错误,react认为您正在尝试显示“li”的对象,但实际上您并没有这样做。

你在错误的地方使用了“绑定”方法。当你在“li”中使用bind时,“this”将被认为是“li”的对象。由于object有一个额外的关键字(onItemClick),因此它不是一个react标签,它是一个具有react li标签属性的js对象。

如果你在Component的构造函数中使用'bind'方法 不会有问题的。但在您的用例中,这是不可能的。所以"(e) =>onItemClick (e,项目)“;

忽略我糟糕的英语。

问题是,当你渲染li时,你是在传递而不是将函数传递给你正在调用它的组件,所以一旦li被渲染,它就会调用它,你需要将引用传递给函数,而不是调用它来做这件事,如果没有参数可以传递,你可以这样写它

onClick={this.onItemClick.bind}

或者像这样,如果有争论要通过

onClick={()=>this.onItemClick.bind(this, item)}

在这种情况下,它将创建一个匿名函数来传递它的引用

我花了半天时间来解决这个问题

我想根据用户是否登录显示一个数组

这是我的代码看起来的样子 return ({ userLogged ? userLoggedCart : cartItems } .map((item)=>{ return //irrelevant code})) 但这是错误的,如果你的代码像这样,你必须把它改成

if (userLogged){ return ( userLoggedCart.map((item)=>{ return //your code }))} else { cartItems.map((item)=>{ return // your code })}

如果你在console.log中打印Object/ Arrays,那么也会出现这个错误。确保添加了JSON。stringify如果你想为对象/数组做console.log

正如我所经历的一样,除了添加"__html"为了标记它,我解决了把标记的HTML到一个span属性" dangerlysetinnerhtml "像下图:

  createMarkup(innerHtml){
return {__html: innerHtml};
}


render = () => {
return (
<span dangerouslySetInnerHTML={
this.createMarkup(this.props.details.entryContent)}/>
);
}

当您尝试将对象呈现为子元素时,可能会发生这种情况,您可以通过查找下面的场景找到根本原因。

  1. 检查你是否在JSX - <span>\{\{value}}</span>中使用了任何双括号,并将其更改为<span>{value}</span>(我犯了这个错误,因为我刚刚从Angular转移到React)。

  2. 检查如下括号括起来的return语句并删除它。

     render() {
    let element = (
    <span>text</span>
    );
    
    
    return (
    {element}  // => Remove this extra brace
    )
    }
    
  3. 检查你在JSX中使用object的任何其他无意的方式

     let nestedObjected = {
    a : '1',
    b : {
    c: '2'
    }
    };
    {Object.keys(nestedObjected).map((key) => {
    return (
    <div>
    <span>{nestedObjected[key]}</span>  // This will cause issue since it will resolve to an object
    </div>
    );
    })}
    

如果你把'async'放在一个功能组件的前面(要么是一个笑话的包装器;反应测试库测试或只是一个普通的旧功能组件),就像这样:

const MockComponent = async () => {
<Provider>
<ComponentImGoingToTest />
</Provider>
}

你期望能够像这样渲染它:

<MockComponent />

然后是两件事:

  1. 你不理解async的含义。
  2. 由于这个关键字,调用包装器函数将调用promise(它是一个对象),而不是JSX归结为预期的React函数。