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

时间:2018-05-16 14:32:47

标签: javascript reactjs react-native

我正在尝试根据AsyncStorage的承诺呈现组件,我收到此错误:

  

异常:不变违规:App(...):没有返回任何内容   渲染。这通常意味着缺少return语句。或者   什么都不渲染,返回null。

我确信组件是好的,因为我试图单独渲染它们并且它们都工作得很好,当我试图通过AsyncStorage.getItem渲染它时我不能完成它。

代码:

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

当我这样做时:

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

效果很好!

当我这样做的时候:

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

它运作良好,所以功能很好,逻辑或者是最重要的东西,我无法工作。

3 个答案:

答案 0 :(得分:2)

AsyncStorage是异步的,因此它不会立即返回您编写的视图。在AsyncStorage检索到您的数据之前,您需要显示微调器或自定义视图。

这是一个解决方案:

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

答案 1 :(得分:0)

嗯,checkToken是一个函数:

  • 调用AsyncStorage
  • 返回undefined

因此,如果日志告诉您渲染没有返回,则日志是正确的!

您应该在checkToken中添加一个return语句。

然后我想我们应该进入第2部分,现在检查令牌是一个函数:

  • 调用AsyncStorage
  • 返回一个Promise,表示将返回执行的函数

它确实不起作用...... React渲染组件,而不是承诺!

我的看法是你需要重构它是如何工作的。我的建议是:

  • 重构checkToken到一个函数,如果getItem成功,则调用setState({content:})
  • 如果失败,则为setState({content:null})
  • 在渲染函数中,不要返回函数调用。相反,请返回state.content
  • 如果您想检查令牌AT EVERY RENDER,请在从渲染中返回state.content之前调用checkToken。
  • 如果您只想检查一次令牌,请在componentDidMount中调用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;
}

答案 2 :(得分:0)

请先使用state来存储令牌。 (你有'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>
        )
      }