496 Stimmen

Rerender-Ansicht beim Browser-Größenänderung mit React

Wie kann ich React dazu bringen, die Ansicht neu zu rendnern, wenn das Browserfenster neu skaliert wird?

Hintergrund

Ich habe einige Blöcke, die ich individuell auf der Seite anordnen möchte, aber ich möchte auch, dass sie sich ändern, wenn sich das Browserfenster ändert. Das Endergebnis wird letztendlich etwas ähnliches wie Ben Hollands Pinterest Layout sein, jedoch geschrieben in React und nicht nur jQuery. Ich bin noch weit davon entfernt.

Code

Hier ist meine App:

var MyApp = React.createClass({
  //führt das http get vom Server aus
  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 (

    );
  }
});

React.renderComponent(
  ,
  document.getElementById('view')
)

Dann habe ich das Block Komponente (entspricht einem Pin im obigen Pinterest Beispiel):

var Block = React.createClass({
  render: function() {
    return (

        {this.props.title}
        {this.props.children}

    );
  }
});

und die Liste/Kollektion von Blocks:

var Blocks = React.createClass({

  render: function() {

    //Ich habe vorübergehend Code, der eine zufällige Position zuweist
    //Siehe innerhalb der folgenden Funktion...

    var blockNodes = this.props.data.map(function (block) {   
      //temporäre zufällige Position
      var topOffset = Math.random() * $(window).width() + 'px'; 
      var leftOffset = Math.random() * $(window).height() + 'px'; 
      return {block.description};   
    });

    return (
        {blockNodes}
    );
  }
});

Frage

Sollte ich das window resize von jQuery hinzufügen? Wenn ja, wo?

$( window ).resize(function() {
  // Komponente neu rendern
});

Gibt es eine "React"-artige Möglichkeit, dies zu tun?

884voto

Sophie Alpert Punkte 133000

Verwendung von React Hooks:

Sie können einen benutzerdefinierten Hook definieren, der auf das resize-Ereignis des Fensters hört, ähnlich wie folgt:

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 Fenstergröße: {width} x {height};
}

Der Vorteil hier ist, dass die Logik gekapselt ist und Sie diesen Hook überall dort verwenden können, wo Sie die Fenstergröße verwenden möchten.

Verwendung von React-Klassen:

Sie können in componentDidMount lauschen, ähnlich wie bei diesem Komponenten, die einfach die Fensterdimensionen anzeigen (wie Fenstergröße: 1024 x 768):

import React from 'react';

class ShowWindowDimensions extends React.Component {
  state = { width: 0, height: 0 };
  render() {
    return Fenstergröße: {this.state.width} x {this.state.height};
  }
  updateDimensions = () => {
    this.setState({ width: window.innerWidth, height: window.innerHeight });
  };
  componentDidMount() {
    window.addEventListener('resize', this.updateDimensions);
  }
  componentWillUnmount() {
    window.removeEventListener('resize', this.updateDimensions);
  }
}

135voto

Andre Pena Punkte 52140

@SophieAlpert hat recht, +1, ich möchte nur eine modifizierte Version ihrer Lösung bereitstellen, ohne jQuery, basierend auf dieser Antwort.

var WindowDimensions = React.createClass({
    render: function() {
        return {this.state.width} x {this.state.height};
    },
    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);
    }
});

66voto

senornestor Punkte 3825

Eine sehr einfache Lösung:

resize = () => this.forceUpdate()

componentDidMount() {
  window.addEventListener('resize', this.resize)
}

componentWillUnmount() {
  window.removeEventListener('resize', this.resize)
}

55voto

voice Punkte 840

Es handelt sich um ein einfaches und kurzes Beispiel zur Verwendung von ES6 ohne jQuery.

import React, { Component } from 'react';

export default class CreateContact extends Component {
  state = {
    windowHeight: undefined,
    windowWidth: undefined
  }

  handleResize = () => this.setState({
    windowHeight: window.innerHeight,
    windowWidth: window.innerWidth
  });

  componentDidMount() {
    this.handleResize();
    window.addEventListener('resize', this.handleResize)
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize)
  }

  render() {
    return (

        {this.state.windowWidth} x {this.state.windowHeight}

    );
  }
}

Haken

import React, { useEffect, useState } from "react";

let App = () => {
  const [windowWidth, setWindowWidth] = useState(0);
  const [windowHeight, setWindowHeight] = useState(0);
  let resizeWindow = () => {
    setWindowWidth(window.innerWidth);
    setWindowHeight(window.innerHeight);
  };

  useEffect(() => {
    resizeWindow();
    window.addEventListener("resize", resizeWindow);
    return () => window.removeEventListener("resize", resizeWindow);
  }, []);

  return (

        {windowWidth} x {windowHeight}

  );
};

42voto

Lead Developer Punkte 1193

Aktualisierung im Jahr 2020. Für React-Entwickler, die Leistung ernst nehmen.

Die oben genannten Lösungen funktionieren ABER sie rendern Ihre Komponenten neu, wenn sich die Fenstergröße um einen einzigen Pixel ändert.

Dies führt oft zu Leistungsproblemen. Daher habe ich den useWindowDimension-Hook geschrieben, der das resize-Ereignis für eine kurze Zeitperiode dämpft, z. B. 100ms.

import React, { useState, useEffect } from 'react';

export function useWindowDimension() {
  const [dimension, setDimension] = useState([
    window.innerWidth,
    window.innerHeight,
  ]);
  useEffect(() => {
    const debouncedResizeHandler = debounce(() => {
      console.log('***** Gedämpftes Resize'); // Sehen Sie den coolen Unterschied in der Konsole
      setDimension([window.innerWidth, window.innerHeight]);
    }, 100); // 100ms
    window.addEventListener('resize', debouncedResizeHandler);
    return () => window.removeEventListener('resize', debouncedResizeHandler);
  }, []); // Beachten Sie dieses leere Array. Dieser Effekt sollte nur beim Mounten und Demounten ausgeführt werden
  return dimension;
}

function debounce(fn, ms) {
  let timer;
  return _ => {
    clearTimeout(timer);
    timer = setTimeout(_ => {
      timer = null;
      fn.apply(this, arguments);
    }, ms);
  };
}

Verwenden Sie es folgendermaßen.

function YourComponent() {
  const [width, height] = useWindowDimension();
  return <>Fensterbreite: {width}, Fensterhöhe: {height};
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X