简体   繁体   English

不变违规:App(...)渲染未返回任何内容

[英]Invariant violation : App(…) Nothing was returned from render

I am trying to render component based on the promise from AsyncStorage and I am getting this error: 我正在尝试根据AsyncStorage的承诺来呈现组件,但出现此错误:

Exception: Invariant Violation: App(...): Nothing was returned from render. 异常:永久违反:App(...):渲染未返回任何内容。 This usually means a return statement is missing. 这通常意味着缺少return语句。 Or, to render nothing, return null. 或者,不渲染任何内容,则返回null。

I know for sure the components are good because I tried to render each of them individually and they're both worked just fine, it's when Im trying to render it through AsyncStorage.getItem I cant make it done. 我肯定知道组件是好的,因为我试图分别渲染每个组件,并且它们都工作得很好,这是我试图通过AsyncStorage.getItem渲染的时候,我无法完成。

CODE: 码:

checkToken = () => {
    AsyncStorage.getItem('user')
        .then((res) => {
            res = JSON.parse(res)
            console.log('this is checkToken()',res.token)
            // this.renderUserSection(res.token);
            return res.token;   
        })
        .then((token) => {
          return (
             <View style={styles.container}> 
                {!token ? this.renderUser() : this.renderApp()} 
             </View>
          )  
        })
        .catch((err) => {
          console.log(err)
        })
}



render() {
    return (
        this.checkToken() 
    ) 
}

When I did : 当我做的时候:

render() {
    return (
        this.renderUser() 
    ) 
}

It worked great! 效果很好!

Also when I did: 同样当我这样做时:

render() {
    return (
        this.renderApp() 
    ) 
}

It worked as well, so the functions are good, is the logic or something at the top one that I can't make work. 它也运行良好,所以功能很好,是我无法执行的逻辑或最重要的东西。

AsyncStorage is asynchronous, so it doesn't immediately return the view you have written. AsyncStorage是异步的,因此它不会立即返回您编写的视图。 You need to display a spinner or a custom view until AsyncStorage has retrieved your data. 在AsyncStorage检索数据之前,您需要显示微调框或自定义视图。

Here's a solution: 这是一个解决方案:

constructor() {
    this.state = {
        token: null
    }
    this.checkToken();
}

checkToken = () => {
    AsyncStorage.getItem('user')
    .then((res) => {
      res = JSON.parse(res)
      console.log('this is checkToken()',res.token)
      // this.renderUserSection(res.token);
    })
    .then((token) => {
        this.setState({token: token})  
    })
    .catch((err) => {
      console.log(err)
    })
}

render() {
    if (this.state.token == null) {
       return (<View> {this.renderUser()} </View>)
    }
    else {
        return (
            <View style={styles.container}> 
               {this.renderApp()}
            </View>
        )
    }
}

Well, checkToken is a function that: 好吧,checkToken是一个函数,该函数:

  • calls AsyncStorage 调用AsyncStorage
  • returns undefined 返回未定义

So if the logs tell you that render returned nothing, the logs are right! 因此,如果日志告诉您渲染未返回任何内容,则日志是正确的!

You should add a return statement to your checkToken. 您应该在您的checkToken中添加一个return语句。

Then I suppose we should get to part 2, now check token is a function that: 然后,我想我们应该进入第2部分,现在检查令牌是一个函数:

  • calls AsyncStorage 调用AsyncStorage
  • returns a Promise that the executed function will be returned 返回一个承诺,将返回执行的函数

It does not really work... React renders components, not promises! 它实际上不起作用... React渲染组件,而不是诺言!

My take is that you need to refactor how this works. 我认为您需要重构它的工作方式。 My suggestion: 我的建议:

  • refactor checkToken into a function that, if getItem succeeds, calls setState({ content: }) 将checkToken重构为一个函数,如果getItem成功,则调用setState({content:})
  • if it fails, setState({ content: null }) 如果失败,则setState({content:null})
  • in your render function, do not return the function call. 在渲染函数中,不要返回函数调用。 Instead, return state.content 而是返回state.content
  • IF you want to check the token AT EVERY RENDER, call checkToken just before returning state.content from render. 如果要在每次渲染时检查令牌,请在从render返回state.content之前调用checkToken。
  • IF you want to check the token just once, call checkToken in componentDidMount instead - or wherever you need. 如果只想检查一次令牌,则改为在componentDidMount中调用checkToken-或在任何需要的地方调用。

This is a sample of what I think the code should look like. 这是我认为代码应该是什么样的示例。 You should think about what's the best place to call checkToken. 您应该考虑调用checkToken的最佳位置。

  checkToken = () => {
    let self = this;
    AsyncStorage.getItem('user')
    .then((res) => {
      res = JSON.parse(res)
      console.log('this is checkToken()',res.token)
      // this.renderUserSection(res.token);
      return res.token;   
    })
    .then((token) => {
      self.setState({
        content: (<View style={styles.container}> 
          {!token ? self.renderUser() : self.renderApp()} 
        </View>)
      });
    })
    .catch((err) => {
      self.setState({ content: null })
      console.log(err)
    })
  }
render() {
  //are you sure you need to call checkToken here? Maybe there's a better place? if there is no shouldComponentUpdate this could cause an infinite re-render loop
  //you could maybe call it for componentDidMount, or some other lifecycle method?
  //otherwise I think you'll need that shouldComponentUpdate implementation.
  this.checkToken();
  return this.state.content;
}

Please use state to store the token first. 请先使用状态存储令牌。 (The method you have 'checkToken' is a void method) (您具有“ checkToken”的方法是无效方法)

checkToken = () => {
        AsyncStorage.getItem('user')
        .then((res) => {
          res = JSON.parse(res)
          console.log('this is checkToken()',res.token)
          // this.renderUserSection(res.token);
          return res.token;
          this.setState(state => ({
            ...state,
            token : res.token
          }))
        })
        .catch((err) => {
          console.log(err)
        })
      }

      render () {
        const { token } = this.state;
        return (
          <View style={styles.container}> 
              {
                !token 
                  ? this.renderUser() 
                  : this.renderApp()
               } 
          </View>
        )
      }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM