Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rerender view on browser resize with React

How can I get React to re-render the view when the browser window is resized?

Background

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.

Code

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>     );   } }); 

Question

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?

like image 829
digibake Avatar asked Sep 25 '13 20:09

digibake


People also ask

How do you measure viewport size in React?

It's the same in React, you can use window. innerHeight to get the current viewport's height.

What is forceUpdate in React?

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.


2 Answers

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);   } } 
like image 84
Sophie Alpert Avatar answered Oct 06 '22 05:10

Sophie Alpert


@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);     } }); 
like image 28
André Pena Avatar answered Oct 06 '22 07:10

André Pena