Is it possible to call a function every time anything in React updates?
A little more context: I want to use the full capabilities of EQCSS in React. I've tried 2 NPM packages, but they didn't seem to do what I expected exactly.
What I would like to do, is every time any component updates, I want to call EQCSS.apply().
I've tried calling in componentDidUpdate but this doesn't seem to work when changing pages (using react-router) for example.
import React from "react";
import ReactDOM from "react-dom";
import { Router, Route, browserHistory } from "react-router";
import { MainLayout } from "./layouts";
import {
HomePage,
RankingsPage
} from "./routes";
class App extends React.Component {
render() {
return (
<Router history={browserHistory}>
<Route component={MainLayout}>
<Route path="/" component={HomePage} />
<Route path="/rankings" component={RankingsPage} />
</Route>
</Router>
);
}
componentDidUpdate() {
console.log("COMPONENT UPDATED");
// This does not get called when changing pages.
}
}
// Render the main component into the dom
ReactDOM.render(<App />, document.getElementById("app"));
Here are three different ways you could achieve this:
React Context
Wrap your main parent component in the MutationObserver. More info here:
MutationObserver will track any changes to the actual DOM tree.
I've demonstrated another approach here: https://codepen.io/PiotrBerebecki/pen/wzqQkx. Please check the console which logs messages every time something has happened on the page, including Route changes, or re-renders of deeply nested children components. This relies however on a callback passed down through the child hierarchy via props.
Ad 1. Context demo code:
class App extends React.Component {
static childContextTypes = {
data: React.PropTypes.bool
};
getChildContext() {
return {data: true};
}
render() {
return (
<div>
<h1>Parent</h1>
<Child />
</div>
)
}
}
class Child extends React.Component {
static contextTypes = {
data: React.PropTypes.bool
};
render() {
console.log('in Child', this.context.data)
return (
<div>
<h3>Child</h3>
<Grandchild />
</div>
);
}
}
class Grandchild extends React.Component {
static contextTypes = {
data: React.PropTypes.bool
};
render() {
console.log('in Grandchild', this.context.data)
return (
<div>
<h6>Grandchild</h6>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
Ad 3. Callback demo code:
var MainLayout = React.createClass({
doSomething: function() {
console.log('something happened');
},
render: function() {
this.doSomething();
const childrenWithProps = React.Children.map(this.props.children,
(child) => React.cloneElement(child, {
doSomething: this.doSomething
})
);
return (
<div className="app">
<header className="primary-header"></header>
<aside className="primary-aside">
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/users">Users</Link></li>
<li><Link to="/widgets">Widgets</Link></li>
</ul>
</aside>
<main>
{childrenWithProps}
</main>
</div>
)
}
})
var Home = React.createClass({
getInitialState: function() {
return {
counter: 1
};
},
componentDidUpdate: function() {
this.props.doSomething()
},
changeCounter: function() {
this.setState({
counter: this.state.counter + 1
});
},
render: function() {
return (
<div>
<button onClick={this.changeCounter}>Click me</button>
<br />
{this.state.counter}
</div>
);
}
})
var SearchLayout = React.createClass({
render: function() {
const childrenWithProps = React.Children.map(this.props.children,
(child) => React.cloneElement(child, {
doSomething: this.props.doSomething
})
);
return (
<div className="search">
<header className="search-header"></header>
<div className="results">
{childrenWithProps}
</div>
<div className="search-footer pagination"></div>
</div>
)
}
})
var UserList = React.createClass({
getInitialState: function() {
return {
counter: 1
};
},
componentDidUpdate: function() {
this.props.doSomething()
},
changeCounter: function() {
this.setState({
counter: this.state.counter + 1
});
},
render: function() {
return (
<div>
User List
<br />
<button onClick={this.changeCounter}>Click me</button>
<br />
{this.state.counter}
</div>
);
}
});
var WidgetList = React.createClass({
getInitialState: function() {
return {
counter: 1
};
},
componentDidUpdate: function() {
this.props.doSomething()
},
changeCounter: function() {
this.setState({
counter: this.state.counter + 1
});
},
render: function() {
return (
<div>
Widgets
<br />
<button onClick={this.changeCounter}>Click me</button>
<br />
{this.state.counter}
</div>
);
}
})
ReactDOM.render((
<Router>
<Route path="/" component={MainLayout}>
<IndexRoute component={Home} />
<Route component={SearchLayout}>
<Route path="users" component={UserList} />
<Route path="widgets" component={WidgetList} />
</Route>
</Route>
</Router>
), document.getElementById('root'))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With