How can I get React to re-render the view when the browser window is resized?
I have some blocks that I want to layout individually on the page, however I also want them to update when the browser window changes. The very end result will be something like Ben Holland's Pinterest layout, but written using React not just jQuery. I’m still a way off.
Here’s my app:
var MyApp = React.createClass({ //does the http get from the server loadBlocksFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', mimeType: 'textPlain', success: function(data) { this.setState({data: data.events}); }.bind(this) }); }, getInitialState: function() { return {data: []}; }, componentWillMount: function() { this.loadBlocksFromServer(); }, render: function() { return ( <div> <Blocks data={this.state.data}/> </div> ); } }); React.renderComponent( <MyApp url="url_here"/>, document.getElementById('view') )
Then I have the Block
component (equivalent to a Pin
in the above Pinterest example):
var Block = React.createClass({ render: function() { return ( <div class="dp-block" style={{left: this.props.top, top: this.props.left}}> <h2>{this.props.title}</h2> <p>{this.props.children}</p> </div> ); } });
and the list/collection of Blocks
:
var Blocks = React.createClass({ render: function() { //I've temporarily got code that assigns a random position //See inside the function below... var blockNodes = this.props.data.map(function (block) { //temporary random position var topOffset = Math.random() * $(window).width() + 'px'; var leftOffset = Math.random() * $(window).height() + 'px'; return <Block order={block.id} title={block.summary} left={leftOffset} top={topOffset}>{block.description}</Block>; }); return ( <div>{blockNodes}</div> ); } });
Should I add jQuery’s window resize? If so, where?
$( window ).resize(function() { // re-render the component });
Is there a more “React” way of doing this?
It's the same in React, you can use window. innerHeight to get the current viewport's height.
Forcing an update on a React class component In any user or system event, you can call the method this. forceUpdate() , which will cause render() to be called on the component, skipping shouldComponentUpdate() , and thus, forcing React to re-evaluate the Virtual DOM and DOM state.
Using React Hooks:
You can define a custom Hook that listens to the window resize
event, something like this:
import React, { useLayoutEffect, useState } from 'react'; function useWindowSize() { const [size, setSize] = useState([0, 0]); useLayoutEffect(() => { function updateSize() { setSize([window.innerWidth, window.innerHeight]); } window.addEventListener('resize', updateSize); updateSize(); return () => window.removeEventListener('resize', updateSize); }, []); return size; } function ShowWindowDimensions(props) { const [width, height] = useWindowSize(); return <span>Window size: {width} x {height}</span>; }
The advantage here is the logic is encapsulated, and you can use this Hook anywhere you want to use the window size.
Using React classes:
You can listen in componentDidMount, something like this component which just displays the window dimensions (like <span>Window size: 1024 x 768</span>
):
import React from 'react'; class ShowWindowDimensions extends React.Component { state = { width: 0, height: 0 }; render() { return <span>Window size: {this.state.width} x {this.state.height}</span>; } updateDimensions = () => { this.setState({ width: window.innerWidth, height: window.innerHeight }); }; componentDidMount() { window.addEventListener('resize', this.updateDimensions); } componentWillUnmount() { window.removeEventListener('resize', this.updateDimensions); } }
@SophieAlpert is right, +1, I just want to provide a modified version of her solution, without jQuery, based on this answer.
var WindowDimensions = React.createClass({ render: function() { return <span>{this.state.width} x {this.state.height}</span>; }, updateDimensions: function() { var w = window, d = document, documentElement = d.documentElement, body = d.getElementsByTagName('body')[0], width = w.innerWidth || documentElement.clientWidth || body.clientWidth, height = w.innerHeight|| documentElement.clientHeight|| body.clientHeight; this.setState({width: width, height: height}); // if you are using ES2015 I'm pretty sure you can do this: this.setState({width, height}); }, componentWillMount: function() { this.updateDimensions(); }, componentDidMount: function() { window.addEventListener("resize", this.updateDimensions); }, componentWillUnmount: function() { window.removeEventListener("resize", this.updateDimensions); } });
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