2016-11-27 118 views
0

我很好奇,为什么在这种情况下做出反应的更新的子组件:为什么React调用未更改组件的渲染方法?

function Inner(props) { 
    console.log("Render Inner"); 
    return <div>Inner</div>; 
} 

export class Outer extends React.Component { 

    constructor(props) { 
    super(props); 
    this.state = { 
     active: false 
    }; 
    this.onClick = this.rawOnClick.bind(this); 
    } 

    render() { 
    console.log("Render Outer"); 
    return <div onClick={this.onClick} style={{ backgroundColor: this.state.active ? 'red': 'blue'}}><Inner/></div>; 
    } 

    rawOnClick(event) { 
    this.setState({ active: !this.state.active }); 
    } 
} 


ReactDOM.render(<Outer/>, document.getElementById('app')); 

当组件外被点击时,内,外的渲染方法被调用。由于组件应该是“纯”的,所以不需要调用Inner的渲染方法,是吗?我甚至可以让它这样,如果我重写我的代码一点点:

export function Inner(props) { 
    console.log("Render Inner"); 
    return <div>Inner</div>; 
} 

export class Outer2 extends React.Component { 

    constructor(props) { 
    super(props); 
    this.state = { 
     active: false 
    }; 
    this.onClick = this.rawOnClick.bind(this); 
    } 

    render() { 
    console.log("Render Outer"); 
    return <div onClick={this.onClick} style={{ backgroundColor: this.state.active ? 'red': 'blue'}}>{this.props.children}</div>; 
    } 

    rawOnClick(event) { 
    this.setState({ active: !this.state.active }); 
    } 
} 

ReactDOM.render(<Outer2><Inner /></Outer2>, document.getElementById('app')); 

现在,当我点击该组件只有“Outer2”的渲染方法被调用。这是故意的吗?这是一项任务优化,还是我错过了一些重要的事情?

谢谢。

Peter

+0

查看更多文档后,我发现我想要的东西:我需要:'this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);'在构造函数中,它具有我期望的行为。我仍然觉得这很奇怪,文档会一直谈论这种“纯粹”渲染,然后忽略它(特别是在“功能”组件中)。但我可以处理。谢谢大家。 – ptriller

+0

对不起,我只需要使用'React.PureComponent'作为基类,并且我有我想要的行为。 – ptriller

回答

1

这是React的默认行为。您必须重写Inner组件中的shouldComponentUpdate()以返回true或false,以确定是否需要再次调用它自己的render()。通常根据当前和下一组道具和状态之间的差异(如果有的话)做出决定。

在你的例子中,你的内部组件总是返回相同的东西,并且不会受到道具或状态改变的影响,你可以返回false。

shouldComponentUpdate(nextProps, nextState) { 
    return false; 
}; 

(注意,你必须从内部无状态的功能转换成ES6类才能使用这种方法的生命周期)。

在官方的文档阅读全文 - https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate

+0

当道具没有改变时,我只是被默认行为所困惑,但只是被设置为相同的值。该文档说:“默认行为是重新呈现每个状态更改....”但由于状态不会更改所有属性设置为相同的值时,我认为它不会呈现。 – ptriller

1

在第一种情况,外部组件的状态在触发点击事件时发生改变。由于状态改变,渲染方法被触发。由于内部组件位于渲染方法内部,因此它也会被渲染并调用内部组件的渲染方法。

由于在第二种情况下,内部组件不在外部组件的渲染方法内,因此即使外部组件的状态发生更改也不会重新渲染。

只有当你没有将外部组件的状态传递给内部组件作为道具时,你的第二种情况才会起作用。只要你这样做,一个状态的关键的改变,作为一个道具传递给内部组件将再次触发内部组件的渲染方法

如果你想传递一些东西从外部组件的状态到内部组件作为道具并避免不必要的内部组件渲染调用,您将不得不从无状态的内部组件移动到基​​于类的内部组件,并使用生命周期方法来限制内部组件的渲染方法不被调用

+0

谢谢。我明白,仍然不是我所期望的,因为React没有创建一个新的Inner组件实例,所以它可以检查它没有改变任何属性并跳过渲染,因为纯合约是有效的。但是,如果这是事实,那就是这样。 – ptriller