无法在 componentWillMount 中设置状态

Posted

技术标签:

【中文标题】无法在 componentWillMount 中设置状态【英文标题】:Can't set state in componentWillMount 【发布时间】:2017-03-05 02:14:38 【问题描述】:

我正在创建一个简单的聊天应用程序,在其中我通过 axios 对我的数据库进行 api 调用,它返回一组消息对象。当我在 componentWillMount 中进行 axios 调用时,我能够获取数据。然后我试图 setState 来显示对话。代码如下:

export default class Chat extends Component 
  constructor(props)
    super(props);

    this.state = 
      messages : [],
      message : '',
    ;
    this.socket = io('/api/');
    this.onSubmitMessage = this.onSubmitMessage.bind(this);
    this.onInputChange = this.onInputChange.bind(this);
  

  componentWillMount() 
    axios.get(`api/messages`)
      .then((result) => 
        const messages = result.data
        console.log("COMPONENT WILL Mount messages : ", messages);
        this.setState( 
          messages: [ ...messages.content ] 
        )
  )
;

我看过一些关于生命周期函数和设置状态的帖子,似乎我在做正确的事情。

再次强调,axios 调用工作正常,设置状态不起作用。我仍然看到一个空数组。提前致谢!

编辑:这是专门针对我的问题的解决方案。它被埋在评论中,所以我想我会把它留在这里..

“我发现了问题。实际上是我如何解析数据。...messages.content 上的扩展运算符不起作用,因为messages.content 不存在。messages[i].content 存在. 所以我的解决方法是只传播 ...messages 然后在一个子组件中映射对象并解析 .content 属性。感谢大家的帮助!”

【问题讨论】:

【参考方案1】:

在您的情况下,您的 setState() 将不起作用,因为您在异步回调中使用 setState()

工作小提琴:https://jsfiddle.net/xytma20g/3/

您正在进行异步 API 调用。因此,setState 只有在接收到数据后才会被调用。它对componentWillMountcomponentDidMount 没有任何作用。您需要在渲染中处理空的message。当您从 API 接收数据时,将该数据设置为状态,组件将使用新状态重新渲染,该状态将反映在您的渲染中。

伪代码:

export default class Chat extends Component 
  constructor(props)
    super(props);

    this.state = 
      messages : [],
      message : '',
    ;
    this.socket = io('/api/');
    this.onSubmitMessage = this.onSubmitMessage.bind(this);
    this.onInputChange = this.onInputChange.bind(this);
  

  componentWillMount() 
    axios.get(`api/messages`)
      .then((result) => 
        const messages = result.data
        console.log("COMPONENT WILL Mount messages : ", messages);
        this.setState( 
          messages: [ ...messages.content ] 
        )
  )

  render()
    if(this.state.messages.length === 0)
     return false //return false or a <Loader/> when you don't have anything in your message[]
    

   //rest of your render.
  
; 

【讨论】:

我正在尝试在发出获取请求时拉起对话,以便对话在重新加载时持续存在。加载程序似乎会给我一个“没有新消息”提示,并且只呈现我从那里输入的新消息。我还考虑在更高级别的组件上发出 GET 请求,以便消息以状态呈现。这是我的渲染方法现在的样子 我发现了这个问题。这实际上是我解析数据的方式。 ...messages.content 上的传播运算符不起作用,因为 messages.content 不存在。 messages[i].content 存在。所以我的解决方法是只传播 ...messages 然后在子组件中映射对象并解析 .content 属性。谢谢大家的帮助! @PhilSeidel 你是个摇滚新星。坚持下去。【参考方案2】:

componentWillMount() 在安装发生之前立即调用。它 在 render() 之前调用,因此在此方法中设置状态将 不会触发重新渲染。避免引入任何副作用或 此方法中的订阅。 docs

所以,你需要打电话给componentDidMount as-

componentDidMount() 
    axios.get(`api/messages`)
      .then((result) => 
        const messages = result.data
        console.log("COMPONENT WILL Mount messages : ", messages);
        this.setState( 
          messages: [ ...messages.content ] 
        )
  )

【讨论】:

您的积分有效。但是,React 将使用新的状态值进行第一次渲染,而不是重新渲染。这就是声明方法不会触发重新渲染的意思。为了您的澄清,我添加了一个工作示例。 jsfiddle.net/q25sfL0z 如果您的 API 调用花费了太多时间来返回响应怎么办? 在这种情况下,您应该使用加载器来指示用户。 我在这里发现,初始渲染和重新渲染是不同的。否则,你的观点是有效的!

以上是关于无法在 componentWillMount 中设置状态的主要内容,如果未能解决你的问题,请参考以下文章

在 componentWillMount 的 redux 检查状态

componentWillMount和componentDidMount的区别

为啥 addChangeListener 应该在 componentDidMount 而不是 componentWillMount 中?

每次在反应本机中聚焦页面时调用 componentWillMount

渲染发生在 ComponentWillMount 之前

在 React.js 中拥有像 componentWillMount 这样的函数的目的是啥?