无法在 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
只有在接收到数据后才会被调用。它对componentWillMount
或componentDidMount
没有任何作用。您需要在渲染中处理空的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 中?