我们说我有一个React元素<Parent
&gt;我需要渲染一个<FooBar>
我的代码目前看起来像
Parent = React.createClass({
getChildren() {
var children = this.props.messages; // this could be 100's
return children.map((child) => {
return <FooBar c={child} />;
});
},
render() {
return (
<div>
{this.getChildren()}
</div>
);
}
});
当有100个孩子因为Parent
等待所有孩子渲染时,这真的很慢。是否有一种解决方法来逐步呈现子项,以便Parent
不必等待其所有子项都呈现?
答案 0 :(得分:1)
您可以一次获取一部分消息进行渲染,然后通过状态计数为更多子项排队进一步更新。
使用requestIdleCallback
或setTimeout
进行排队将允许您逃避React的状态批处理以拦截当前的浏览器绘制,如果您直接setState
这将是一个问题来自componentDidUpdate
有什么能让你前进
const Parent = React.createClass({
numMessagesPerRender = 10
constructor(props) {
super(props)
this.state = {
renderedCount: 0
}
}
componentWillReceiveProps(props) {
// must check that if the messages change, and reset count if you do
// you may also need to do a deep equality of values if you mutate the message elsewhere
if (props.messages !== this.props.messages) {
this.setState({renderedCount: 0})
}
}
getChildren() {
// take only the current
const children = this.props.messages.slice(0, this.state.renderedCount);
return children.map(child => <FooBar c={child} />);
},
render() {
return (
<div>
{this.getChildren()}
</div>
);
}
renderMoreMessagesPlease() {
// you MUST include an escape condition as we are calling from `componentDidXYZ`
// if you dont your component will get stuck in a render loop and crash
if (this.state.renderedCount < this.props.messages.length) {
// queue up state change until the frame has been painted
// otherwise setState can halt rendering to do batching of state changes into a single
// if your browser doesnt support requestIdleCallback, setTimeout should do same trick
this.idleCallbackId = requestIdleCallback(() => this.setState(prevState => ({
renderedCount: prevState.renderedCount + this.numMessagesPerRender
})))
}
}
componentDidMount() {
this.renderMoreMessagesPlease()
}
componentDidUpdate() {
this.renderMoreMessagesPlease()
}
componentDidUnmount() {
// clean up so cant call setState on an unmounted component
if (this.idleCallbackId) {
window.cancelIdleCallback(this.idleCallbackId)
}
}
});
答案 1 :(得分:0)
你应该利用承诺和国家。这是一个简单的解决方案。
Parent = React.createClass({
getInitialState() {
return {
children: []
}
},
componentDidMount() {
var prom = new Promise(function(resolve, reject){
if (this.props.messages) {
for(var i = 0;i < this.props.messages.length; i++) {
const children = this.state.children;
children.push(this.props.messages[i]);
this.setState({children});
}
resolve();
}
else {
reject();
}
})
prom.then(()=>{
console.log('All children added')
}).catch(()=>{
console.log('could not get props.messages')
})
},
render() {
return (
<div>
{this.state.children.map((child)=>(<FooBar c={child} />))}
</div>
);
}
});