【问题标题】:Can't set state in componentWillMount无法在 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 属性。感谢大家的帮助!”

【问题讨论】:

    标签: javascript reactjs state


    【解决方案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 调用花费了太多时间来返回响应怎么办?
    • 在这种情况下,您应该使用加载器来指示用户。
    • 我在这里发现,初始渲染和重新渲染是不同的。否则,你的观点是有效的!
    猜你喜欢
    • 1970-01-01
    • 2020-08-26
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    相关资源
    最近更新 更多