I'm exploring React 16. One of the new features of this version is Async Rendering (aka Fiber). It is said that componentWillMount
is unsafe because it can be called multiple times and sometimes it will cause unwanted side effects. I'd read this document https://github.com/acdlite/react-fiber-architecture and watched this video https://www.youtube.com/watch?v=aV1271hd9ew&feature=youtu.be but I can't find working example of such behaviour of componentWillMount
.
In this questions:
- React componentWillUpdate getting called twice
- Why might componentWillMount be called multiple times with React Fibre?
it is said that componentWillMount
may be called several times when high priority event occurs during rendering process.
So I tried to make it myself using create-react-app
and React.js 16.11.0. My idea is to build big react tree and add css animation on root component.
JSX:
class RecursiveComponent extends React.Component {
componentWillMountCalledTimes = 0;
componentWillMount() {
this.componentWillMountCalledTimes++;
if (this.componentWillMountCalledTimes > 1) {
console.log(`Mounting ${this.props.depth} call ${this.componentWillMountCalledTimes}`);
}
}
render() {
if (this.props.depth > 0) {
if (this.props.depth % 2) {
return (
<div>
<RecursiveComponent depth={this.props.depth - 1} />
</div>
);
} else {
return (
<span>
<RecursiveComponent depth={this.props.depth - 1} />
</span>
);
}
} else {
return <div>Hello world</div>;
}
}
}
class App extends React.Component {
state = {
depth: 1000,
}
componentDidMount() {
setInterval(() => {
this.setState({ depth: 1001 + this.state.depth % 10 });
}, 1000);
}
render() {
return (
<div className={'App'}>
<RecursiveComponent depth={this.state.depth} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
styles:
.App {
width: 400px;
height: 400px;
background-color: red;
animation-duration: 3s;
animation-name: slidein;
animation-iteration-count: infinite;
}
@keyframes slidein {
from {
margin-left: 300px;
}
to {
margin-left: 0;
}
}
I expect smooth animation and rare console output but there is no messages in console. What is my mistake? How can I demonstrate multiple calls of componentWillMount
function?
Upd:
As @DoXicK mentioned Async Rendering is disabled by default in current version of React.JS. I'd followed by this guide https://reactjs.org/docs/concurrent-mode-adoption.html and write such example
import React from 'react';
import './App.css';
class Caption extends React.Component {
componentWillMountCalledTimes = 0;
componentWillMount() {
wait(100);
this.componentWillMountCalledTimes++;
if (this.componentWillMountCalledTimes > 1)
console.log(`Mounting ${this.props.depth} call ${this.componentWillMountCalledTimes}`);
}
render() {
return <div>{this.props.children}</div>;
}
}
class App extends React.Component {
state = { counter: 0 }
componentDidMount() {
setInterval(() => {
this.setState({ counter: this.state.counter + 1 });
}, 100);
}
render() {
if (this.state.counter % 10 === 0) {
return <div>Empty</div>;
} else {
return (
<div className={'App'}>
<Caption>{'Hello 1'}</Caption>
<Caption>{'Hello 2'}</Caption>
<Caption>{'Hello 3'}</Caption>
</div>
);
}
}
}
function wait(time) {
const start = Date.now();
while (Date.now() - start < time) {
}
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
I'd used CSS from the example above. I'd expected to get at least one message about multiple call of componentWillMount
on one element (because each element renders more than , but I had no luck.
I think I'm missing something but I don't understand what.