componentWillReceiveProps不触发

23

在我的其他课程中,componentWillReceiveProps很好地运行了,但出于某种原因,在这里它没有触发。

ItemView.jsx

class ItemView extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            name: null, 
            rating: null, 
            sector: null, 
            location: null, 
            description: null, 
            image: "blank.png",
            show: false
       };
    }

    ...

    componentWillReceiveProps(nextProps) {

        if(!nextProps.companyToRender) {
            this.setState({
                name: null, 
                rating: null, 
                sector: null, 
                location: null, 
                description: null, 
                image: "blank.png",
                show: false
            });
       }
       else {
           var companyToRender = nextProps.companyToRender;

           this.setState({
               name: companyToRender.name, 
               rating: companyToRender.rating, 
               sector: companyToRender.sector, 
               location: companyToRender.location, 
               description: companyToRender.description, 
               image: companyToRender.image,
               show: true
           });
    }

    ...

    render () {
       return(
        <div>
         ...
        <CommentBox show={this.state.show} companyToRender={this.state.name}/>
         ...
        </div>
       );

    }
}

评论框组件 CommentBox.jsx

class CommentBox extends React.Component {
    constructor(props) {
        super(props);
        this.state = {companyToRender: null};
    }

    componentWillReceiveProps(nextProps) {
        this.setState({companyToRender: nextProps.companyToRender});
    }

    ...
}

传递给itemView的prop要么为null(如果不需要传递任何内容),要么是ItemView分配给它的数组。

当状态属性变为null时,componentWillReceiveProps()才会触发,而不是当它被设置时。((null --> entry)无效,但(entry --> null)有效)。

我是否漏掉了什么?谢谢!

-- 编辑:

(null --> entry)更新状态,但不调用日志或任何后续的componentWillRecieveProps()。(但entry --> null会)

null --> entry的日志

entry --> null的日志


你是否已经在ItemViewcomponentWillReceiveProps或通过Chrome的react检查器插件验证了name状态是否被正确设置?这听起来像是ItemView没有重新渲染,因为name没有改变。 - Rose Robertson
我尝试在CommentBox.jsx的componentWillReceiveProps()函数和render()函数中记录日志。奇怪的是,它不会在componentWilRecieveProps()函数内打印日志,但会在null-->entry期间在render()函数内更改状态。我将更新该条目以显示在Chrome上的输出。 - Carlo Pascual
传递给itemView的prop要么为空(如果不需要传递任何内容),要么是ItemView正在分配给它的数组。 你的问题中,是不是只是一个错误?或者companyToRender是一个数组(如你所说)?我猜应该是一个对象。 此外,请注意当组件初次挂载时,componentWillReceiveProps方法不会被调用(只有之后才会调用)。 - fabio.sussetto
4个回答

25

经过痛苦的调试,我发现问题是ItemView被调用在一个模态框(react-bootstrap)中,由于某些原因,它不支持componentWillReceiveProps()。最终通过重构代码解决了这个问题。谢谢大家!


你在网上找到了这个的确认信息还是已经提交了一个bug? - ruffin
13
非常有道理!由于模态框每次更改都必须创建全新的组件,所以 componentWillReceiveProps 从未被调用(它只应在有 属性时被调用,而不是初始属性)。尝试将您的属性逻辑放在 constructor() 中!同时,感谢您节省了大量调试时间。 - James M. Lay
2
感谢跟进并发布问题所在!我刚使用 react-modal 创建的模态框中出现了同样的问题,你的答案很快让我发现了问题。 - rockfakie
2
发生在我身上,使用另一个库的模态框,将代码放在构造函数中使其工作。谢谢@JamesM.Lay - dixitk13

14

如果其他人也遇到了此问题...

componentWillReceiveProps方法只有在收到与之前完全不同的props时才会被调用。 如果你想要传递相同的prop,可以添加一个虚假的prop,每次向组件发送相同的prop时都进行迭代,以防该组件在内部重置自身。

click() {
    this.setState({counter: ++this.state.counter, unchangingProp:true})
}
<Component unchangingProp={this.state.unChangingProp} counter={this.state.counter}/>

这样componentWillReceiveProps将会在每次触发。


不知何故,更新组件状态也没有触发 componentWillReceiveProps - Johhan Santana
@JohhanSantana 这是 React 生命周期中预期的行为,你可以参考这张图片来了解正在发生的事情。 - Kaijiro
我认为这很令人困惑,可能会导致用户做出错误的架构选择和反模式。我建议考虑模式和反模式时,请查阅React文档。例如,可以参考这个页面:https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html - Nadav Lebovitch
这是一种快速而不太规范的方法。如果您有更好的解决方案,请发帖,我会点赞。 - Leon

6

在我的情况下,每次渲染时都会重新创建我的组件,因此我不得不将逻辑放在构造函数中。我知道这不是理想的解决方案,但这是一个简单的组件,相对于尝试修复导致组件每次重新创建的问题,这样做对我来说更容易。


2
如果你必须将逻辑放在构造函数中,尝试使用componentDidMount代替。它应该与构造函数同时触发。 - Tomasz Czechowski

2

我也遇到了同样的问题。如果有人在直接输入URL时,componentwillreceiveprops不会触发。我也不得不重构我的代码才能让它正常工作。

我所做的更改是在我的初始index.tsx中添加了类似以下内容(即将路由器作为外部元素):

render( 
<Router history={hashHistory} >
{routes}
</Router>
, document.getElementById('root'));

我的默认路由是指向我的app.tsx页面,其结构如下:

render() {

return (
 <Provider store={store}>
   <div id="appContainer">
           {this.props.children}
   </div>
 </Provider>
);

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接