【问题标题】:Invariant violation : App(...) Nothing was returned from render不变违规:App(...) 没有从渲染返回
【发布时间】:2018-05-16 14:32:47
【问题描述】:

我正在尝试根据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() 
    ) 
}

它工作得很好,所以功能很好,是逻辑或顶部的东西我无法工作。

【问题讨论】:

  • 哎呀,你确定承诺响应中的 this 实际上指向了具有 renderuser renderApp 函数的对象吗?
  • 在 ES6 中使用箭头函数声明函数时,会将 this 绑定到它。
  • 好的,只是为了排除这些函数在另一个作用域之类的东西。

标签: javascript reactjs react-native


【解决方案1】:

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

【讨论】:

  • 在不安全的状态下存储token 吗?
  • @FabioLolli 我不这么认为。无论如何,它都存储在未加密的 AsyncStorage 中。
  • 好吧,这种方法的问题是每次用户关闭应用程序时都会刷新state,因此他每次都必须重新登录。这是我尝试的第一种方法,但它不适合存储和检查令牌。我得想办法根据实际AsyncStorage进行检查和渲染
  • @obiwankenoobi 我不认为用户每次都需要登录。每次呈现视图时,它都会从存储中获取令牌并具有一些价值,与检查实际的AsyncStorage 没有区别。
  • 每个渲染周期会调用constructor 中的什么内容?
【解决方案2】:

请先使用状态存储令牌。 (你有'checkToken'的方法是一个void方法)

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

【讨论】:

  • 不是在应该不安全的状态下存储一个名为token 的变量吗?
  • @FabioLolli 不确定它是否安全,但您可以简单地保留一个 bool,因为您只需要知道它是否存在。
  • 好吧,这种方法的问题是每次用户关闭应用程序时都会刷新state,因此他每次都必须重新登录。这是我尝试的第一种方法,但它不适合存储和检查令牌。我得想办法根据实际的AsyncStorage进行检查和渲染
【解决方案3】:

好吧,checkToken 是一个函数:

  • 调用 AsyncStorage
  • 返回未定义

因此,如果日志告诉您渲染没有返回任何内容,那么日志是正确的!

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

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

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

它并没有真正起作用...... React 渲染组件,而不是承诺!

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

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

【讨论】:

    猜你喜欢
    • 2019-07-04
    • 2018-08-11
    • 2019-08-18
    • 2020-07-11
    • 2020-12-11
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2016-07-31
    相关资源
    最近更新 更多