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?

4voto

Nicolay Hekkens Punkte 530
componentDidMount() {

    // Behandle die Größeänderung
    window.addEventListener('resize', this.handleResize);
}

handleResize = () => {
    this.renderer.setSize(this.mount.clientWidth, this.mount.clientHeight);
    this.camera.aspect = this.mount.clientWidth / this.mount.clientHeight;
    this.camera.updateProjectionMatrix();
};

Nur die Resize-Ereignisfunktion definieren.

Dann die Größe des Renderers (Canvas) aktualisieren und ein neues Seitenverhältnis für die Kamera zuweisen.

Meiner Meinung nach ist das Deaktivieren und erneute Aktivieren eine verrückte Lösung....

Hier ist das mount, falls benötigt.

3voto

kimbaudi Punkte 10785

Nur um @senornestors Lösung zu verbessern, forceUpdate zu verwenden und @gkris Lösung, den resize Event-Listener beim Komponentenentfernen zu entfernen:

  1. Vergessen Sie nicht, den Aufruf von resize zu drosseln (oder zu verzögern)
  2. Stellen Sie sicher, dass Sie bind(this) im Konstruktor verwenden

    import React from 'react' import { throttle } from 'lodash'

    class Foo extends React.Component { constructor(props) { super(props) this.resize = throttle(this.resize.bind(this), 100) }

    resize = () => this.forceUpdate()

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

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

    render() { return ( {window.innerWidth} x {window.innerHeight} ) } }

Ein weiteres Verfahren ist, einfach einen "Dummy"-Zustand anstelle von forceUpdate zu verwenden:

import React from 'react'
import { throttle } from 'lodash'

class Foo extends React.Component {
  constructor(props) {
    super(props)
    this.state = { foo: 1 }
    this.resize = throttle(this.resize.bind(this), 100)
  }

  resize = () => this.setState({ foo: 1 })

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

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

  render() {
    return (
      {window.innerWidth} x {window.innerHeight}
    )
  }
}

2voto

Russell Cohen Punkte 697

https://github.com/renatorib/react-sizes ist ein HOC, um dies zu tun und gleichzeitig eine gute Leistung beizubehalten.

import React from 'react'
import withSizes from 'react-sizes'

@withSizes(({ width }) => ({ isMobile: width < 480 }))
class MyComponent extends Component {
  render() {
    return {this.props.isMobile ? 'Ist Mobil' : 'Ist nicht Mobil'}
  }
}

export default MyComponent

2voto

Jim Perris Punkte 2565

Musste es im Konstruktor an 'this' binden, um es mit Klassensyntax zum Laufen zu bringen

class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.resize = this.resize.bind(this)      
  }
  componentDidMount() {
    window.addEventListener('resize', this.resize)
  }
  componentWillUnmount() {
    window.removeEventListener('resize', this.resize)
  }
}

2voto

dumorango Punkte 136

Vielen Dank für alle Antworten. Hier ist mein React + Recompose. Es ist eine High-Order-Funktion, die die Eigenschaften windowHeight und windowWidth zum Komponenten hinzufügt.

const withDimensions = compose(
 withStateHandlers(
 ({
   windowHeight,
   windowWidth
 }) => ({
   windowHeight: window.innerHeight,
   windowWidth: window.innerWidth
 }), {
  handleResize: () => () => ({
    windowHeight: window.innerHeight,
    windowWidth: window.innerWidth
  })
 }),
 lifecycle({
   componentDidMount() {
   window.addEventListener('resize', this.props.handleResize);
 },
 componentWillUnmount() {
  window.removeEventListener('resize');
 }})
)

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