【问题标题】:Invariant Violation: Objects are not valid as a React child when firing a function不变违规:触发函数时,对象作为 React 子项无效
【发布时间】:2019-06-26 18:42:48
【问题描述】:

如果this.state.number 等于数组中的数字,则触发此函数时会出现问题。

  delay = async () => {
     const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
     await sleep(1000);
     return <Redirect to="/dashboard" />
  }

错误

Invariant Violation:对象作为 React 子对象无效(发现: [对象承诺])。如果你打算渲染一组孩子, 改为使用数组。

Home.js

import React, {Component} from 'react';
import {Redirect} from "react-router-dom";
import Grid from '@material-ui/core/Grid';
import './App.css';
import { withRouter } from 'react-router-dom'

class Home extends Component {

    state = {
        number: "",

        numbers: ["111-111-1112, 111-111-1111, 111-111-1116, 111-111-1118"]
      };


      onChange = e => {
        e.preventDefault();

        this.setState({
          number: e.target.value
        });
      };

      delay = async () => {
        const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
        await sleep(1000);
        return <Redirect to="/dashboard" />
      }

      validate = myNum => this.state.numbers.find(num => num === myNum);
      render(){

        const validatedNumber = (
          <div>
            <span style={{ color: "green" }}>Activated ✅ </span>
            {this.delay()}
          </div>
        );
        return (
          <div className="main">
             <Grid container >
               <Grid item sm={8} md={12} >
                <input
                type="text"
                placeholder="Validate Number"
                value={this.state.number}
                onChange={this.onChange}
                />
            <h2>
              {this.validate(this.state.number) ? (
                validatedNumber
              ) : (
                <div>Not in the system</div>
              )}
            </h2>

               </Grid>   

             </Grid>

          </div>
        );

      }
}

export default Home;

【问题讨论】:

  • 你不能“兑现”承诺。您应该在 return/jsx 之外调用该方法,而不是那样做。定时器完成时设置一个状态变量。并从该状态变量呈现重定向
  • 或者您可以在超时结束时以编程方式重定向。
  • @AvinKavish 是的,但由于操作使用react-router-dom,因此约定是呈现重定向。两者都可以工作:)
  • 约翰你能提供一个答案来说明你会怎么做吗?

标签: reactjs


【解决方案1】:

您收到此错误是因为 this.delay() 将返回一个 Promise 对象并且您无法渲染对象。

任何具有async 的函数都会返回Promise

要解决这个问题,您需要一个if 来决定返回什么,以及一个状态来保持statusstatus

  1. 保持shouldRedirect的状态

    state = {
       ...
       shouldRedirect: false
    }
    
  2. setTimeout 完成时更新状态

    delay = async () => {
        const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
        await sleep(1000);
        this.setState({shouldRedirect: true})
    }
    
  3. 如果shouldRedirect,则检查渲染方法

    render(){
        if(this.state.shouldRedirect){
            return <Redirect to="/dashboard" />
        }
        // continue with normal render
        ...
    }
    
  4. 在正确的地方拨打delay

    onChange = e => {
        e.preventDefault();
        let number = e.target.value
        this.setState({number});
        if(this.state.numbers.find(num => num === number)){
            this.delay()
        }
    };
    

【讨论】:

  • 使用withRouter 然后this.props.history.push("/dashboard") 可能更简单。
  • @AnttiPihlaja 是的,这好多了!但是因为 OP 使用的是&lt;Redirect /&gt;,所以我使用它提供了答案。
  • @BARNOWL 我添加了调用它的方式,因此它保持相同的功能:)
  • @BARNOWL 将原始呼叫 {this.delay()} 移至 onChange 时,您是否删除了它?
  • 它现在可以工作了,感谢您的解释和帮助。
【解决方案2】:

您必须在将事件的值传递给setState 之前捕获它,否则事件可能会在设置状态之前超出范围。

import React, {Component} from 'react';
import {Redirect} from "react-router-dom";
import Grid from '@material-ui/core/Grid';
import './App.css';
import { withRouter } from 'react-router-dom'

class Home extends Component {
    state = {
        number: "",
        numbers: ["111-111-1112, 111-111-1111, 111-111-1116, 111-111-1118"],
        isValid: false
      };

      onChange = e => {
        const number = e.target.value
        this.setState({ number });
        if (this.isValid(number)) {
          setTimeout(() => this.props.history.push('/dashboard'), 1000)
          this.setState({ isValid: true })
        }
      };

      isValid = myNum => this.state.numbers.find(num => num === myNum);

       render() {
        const { number, isValid } = this.state
        return (
          <div className="main">
             <Grid container >
               <Grid item sm={8} md={12} >
                <input
                  type="text"
                  placeholder="Validate Number"
                  value={number}
                  onChange={this.onChange}
                />
                <h2>
                 {isValid ? (
                  <div>
                    <span style={{ color: "green" }}>Activated ✅ </span>
                  </div>
                 ) 
                 : (
                   <div>Not in the system</div>
                )}
              </h2>
            </Grid>   
          </Grid>
        </div>
       );
     }
}
export default withRouter(Home);

【讨论】:

    【解决方案3】:

    不是正确的方法,但如果你愿意,你可以做一些奇怪的事情:

    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          asyncjsx: null
        };
      }
    
      delay = async () => {
        const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
        await sleep(3000);
        return <div>second</div>;
      };
    
      render() {
        (async () => {
          this.setState({ asyncjsx: await this.delay() });
        })();
    
        return (
          <>
            <div>first</div>
            {this.state.asyncjsx && this.state.asyncjsx}
          </>
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-13
      • 2018-12-16
      • 2019-09-09
      • 2020-04-26
      • 1970-01-01
      • 2020-01-25
      • 2017-09-24
      • 2020-07-25
      • 1970-01-01
      相关资源
      最近更新 更多