2015-06-12 176 views
19

我有一个React组件,里面有许多子组件。我想不是一次渲染孩子组件,而是延迟一段时间(每个孩子都是统一的或不同的)。React组件的延迟渲染

我想知道 - 有没有办法如何做到这一点?

getInitialState() { 
    let state = {}; 
    React.Children.forEach(this.props.children, (child, index) => { 
     state[index] = false; 
    }); 
    return state; 
} 

然后,当:

回答

29

我认为最直观的方法是给孩子一个“等待”prop,它隐藏组件从父辈传递下来的时间。通过将默认状态设置为隐藏状态,React将立即渲染组件,但在状态更改之前它不可见。然后,您可以设置componentWillMount来调用一个函数,以在通过道具传递的持续时间之后显示它。

var Child = React.createClass({ 
    getInitialState : function() { 
     return({hidden : "hidden"}); 
    }, 
    componentWillMount : function() { 
     var that = this; 
     setTimeout(function() { 
      that.show(); 
     }, that.props.wait); 
    }, 
    show : function() { 
     this.setState({hidden : ""}); 
    }, 
    render : function() { 
     return (
      <div className={this.state.hidden}> 
       <p>Child</p> 
      </div> 
     ) 
    } 
}); 

然后,在父组件中,您需要做的就是传递希望孩子在显示它之前等待的持续时间。

var Parent = React.createClass({ 
    render : function() { 
     return (
      <div className="parent"> 
       <p>Parent</p> 
       <div className="child-list"> 
        <Child wait={1000} /> 
        <Child wait={3000} /> 
        <Child wait={5000} /> 
       </div> 
      </div> 
     ) 
    } 
}); 

Here's a demo

+0

非常感谢您的回答!完全按照我的需要工作。 – michalvalasek

+0

你从哪里得到那个show property?那不是React的一部分吗? – PositiveGuy

+0

'show'指的是我创建的函数,它将'hidden'状态设置为空字符串。这是'Child'类的第三个功能。 –

7

在你父亲组件<Father />,你可以(使用和id为实例),分配一个布尔值,这意味着呈现不创造一个可以跟踪每一个孩子的初始状态该组件安装,您启动定时器来改变状态:

componentDidMount() { 
    this.timeouts = React.Children.forEach(this.props.children, (child, index) => { 
     return setTimeout(() => { 
       this.setState({ index: true; }); 
     }, child.props.delay); 
    }); 
} 

当你渲染你的孩子,你通过重新创建他们这样做,分配为道具的匹配子说,如果组件必须的状态被渲染或不被渲染。

let children = React.Children.map(this.props.children, (child, index) => { 
    return React.cloneElement(child, {doRender: this.state[index]}); 
}); 

所以在你<Child />组件

render() { 
    if (!this.props.render) return null; 
    // Render method here 
} 

当超时被触发,状态改变和父亲组件重新呈现。儿童道具更新了,如果doRendertrue,他们会渲染自己。

+0

非常感谢您的回答!虽然我选择了迈克尔的答案(因为它更适合我的情况),但你的答案是**也是正确的,并且可能适合其他读者阅读。非常感谢您的时间! – michalvalasek

+0

总是乐于帮助...并且它可以培养任何未来的想法:) – gcedo

2

取决于你的使用情况。

如果你想做一些动画混合的儿童,使用反应动画插件:https://facebook.github.io/react/docs/animation.html 否则,使小孩的渲染依赖道具并在延迟后添加道具。

我不会在组件中延迟,因为它可能会在测试过程中困扰你。理想情况下,组件应该是纯粹的。

0

我的用例可能有点不同,但认为发布我提出的解决方案可能很有用,因为它采用了不同的方法。

基本上我有一个第三方Popover组件,它需要一个锚DOM元素作为道具。问题是我无法保证anchor元素会立即在那里,因为锚元素在我想要锚定的Popover的同时变为可见(在同一个redux派发期间)。

一个可能的解决方法是将Popover元素放置到组件树中,而不是将它锚定到的元素。但是,这不符合我的组件的逻辑结构。

最终我决定延迟(再)呈现酥料饼成分的一点点,以确保锚DOM元素都可以找到。它使用功能为儿童样式只呈现一个固定的延时后的孩子:

import { Component } from 'react' 
import PropTypes from 'prop-types' 

export default class DelayedRender extends Component { 
    componentDidMount() { 
     this.t1 = setTimeout(() => this.forceUpdate(), 1500) 
    } 

    componentWillReceiveProps() { 
     this.t2 = setTimeout(() => this.forceUpdate(), 1500) 
    } 

    shouldComponentUpdate() { 
     return false 
    } 

    componentWillUnmount() { 
     clearTimeout(this.t1) 
     clearTimeout(this.t2) 
    } 

    render() { 
     return this.props.children() 
    } 
} 

DelayedRender.propTypes = { 
    children: PropTypes.func.isRequired 
} 

它可以像这样使用:

<DelayedRender> 
    {() => 
     <Popover anchorEl={getAnchorElement()}> 
      <div>Hello!</div> 
     </Popover> 
    )}} 
</DelayedRender> 

感觉相当哈克给我,但适合我的使用情况不过。