React ile tarayıcı boyutunu yeniden boyutlandırın


313

Tarayıcı penceresi yeniden boyutlandırıldığında React'ın görünümü yeniden oluşturmasını nasıl sağlayabilirim?

Arka fon

Sayfada ayrı ayrı düzenlemek istediğim bazı bloklarım var, ancak tarayıcı penceresi değiştiğinde bunların güncellenmesini de istiyorum. En son sonuç Ben Holland'ın Pinterest düzeni gibi bir şey olacak , ancak React kullanılarak sadece jQuery kullanılarak yazılmayacak. Hala bir çıkış yolum var.

kod

İşte benim 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')
)

Sonra Blockbileşen var ( Pinyukarıdaki Pinterest örneğinde bir eşdeğer ):

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

ve aşağıdakilerin listesi / koleksiyonu 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>
    );
  }
});

Soru

JQuery'nin pencere yeniden boyutlandırmasını eklemeli miyim? Öyleyse, nerede?

$( window ).resize(function() {
  // re-render the component
});

Bunu yapmanın daha “Tepki” yolu var mı?

Yanıtlar:


531

Reaksiyon Kancalarını Kullanma:

Pencere resizeolayını dinleyen özel bir Kanca tanımlayabilirsiniz , şöyle:

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

Buradaki avantaj, mantığın kapsüllenmiş olmasıdır ve bu Kancayı pencere boyutunu kullanmak istediğiniz her yerde kullanabilirsiniz.

React sınıflarını kullanma:

Sadece pencere boyutlarını görüntüleyen (gibi <span>Window size: 1024 x 768</span>) bir bileşen gibi componentDidMount'ta dinleyebilirsiniz :

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

5
Bu nasıl çalışıyor? this.updateDimensionsİletilen addEventListeneriçin bir değere sahip olacaktır sadece çıplak fonksiyon referans thisgeçerli olacaktır. Anonim bir işlev veya bir .bind () çağrısı eklemek için kullanılmalı mı thisyoksa yanlış mı anlaşıldım?
fadedbee

24
@chrisdew Burada biraz geç kaldım, ancak React thisdoğrudan bileşen üzerinde tanımlanan herhangi bir yöntem için otomatik olarak bağlanır .
Michelle Tilley

3
@MattDell evet, ES6 sınıfları sadece normal sınıflardır, bu nedenle onlarla otomatik olarak bağlanmaz.
Michelle Tilley

30
Hayır jQuery gerekli - kullanım innerHeightve innerWidthgelen window. Ve atlayabilirsiniz componentWillMountkullanırsanız getInitialStateayarlamak heightve width.
sighrobot

2
Gibi @MattDell görünüyor ::bağlama sözdizimi şimdilik çıktı sitepoint.com/bind-javascripts-this-keyword-react ( "bağlama operatörü: :) ES7 takımı bulunmaktadır olarak Şubat ayında donduruldu, ES7 parçası olmak gitmiyor , bağlayıcı operatörü ES8 için bir teklif "
Jarrod Smith

130

@SophieAlpert doğru, +1, sadece bu cevaba dayanarak jQuery olmadan çözümünün değiştirilmiş bir sürümünü sunmak istiyorum .

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

sadece vanilya JS olay dinleyicileri için IE ile ilgili çoklu doldurma ayarlarınız olduğunda çalışır
nnnn

@nnnn detaylandırabilir misin? Bunu yalnızca Chrome'da test ettiğimi itiraf ediyorum. Window.addEventListener'ın çoklu dolgular olmadan IE üzerinde çalışmayacağını mı söylüyorsunuz?
André Pena

2
@andrerpena caniuse.com/#search=addeventlistener ie8'in bir sorunla karşı karşıya olduğunu gösterir
nnnn

2
@nnnn. Anlıyorum. Evet .. Yani çözümüm IE 8 üzerinde çalışmıyor, ancak 9'dan :) çalışıyor. Teşekkürler.
André Pena

35
IE8'i gerçekten önemseyen var mı? Yoksa sadece alışkanlık mı?
16:41

48

Çok basit bir çözüm:

resize = () => this.forceUpdate()

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

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

12
Kuvvet güncellemesini azaltmayı unutmayın, yoksa çok glitchy görünecektir.
k2snowman69

4
Ayrıca dinleyiciyi kaldırmayı da unutmayın componentWillUnmount()!
Jemar Jones

Kısılırsa bu en iyi çözümdür. Yani forceUpdateşartlı olarak uygulanırsa
asmmahmud

1
Kısıltılması gereken forceUpdate (denilen şey) değil, kısılması gereken yeniden boyutlandırma olayı tetiklemesi (tetiklenen şey). Bir pencereyi büyükten küçüğe yeniden boyutlandırdığınızda, yeniden boyutlandırma olayları teknik olarak her pikselde çağrılabilir. Bir kullanıcı bunu hızlı bir şekilde yaptığında, bu sizin umduğunuzdan daha fazla olaydır. Daha da kötüsü, UI iş parçacığını Javascript iş parçacığına bağlarsınız, bu da uygulamanızın her bir etkinliği ayrı ayrı ele almaya çalışırken ciddi derecede yavaş bir his almaya başlayacağı anlamına gelir.
1919

1
Yeniden boyutlandırma işlevini her pikselde çalıştırmak yerine, her zaman ilk ve son olayı işlediğiniz akışkanlık yanılsamasını vermek ve böylece yeniden boyutlandırmayı akıcı bir şekilde gerçekleştirdiğini hissetmek için kısa bir periyodik süre çalıştırırsınız.
1919

42

JQuery olmadan es6 kullanmanın basit ve kısa bir örneğidir.

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 (
      <span>
        {this.state.windowWidth} x {this.state.windowHeight}
      </span>
    );
  }
}

kancalar

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 (
    <div>
      <span>
        {windowWidth} x {windowHeight}
      </span>
    </div>
  );
};

4
Bu güzel, kısa ve öz bir cevap ama AFAICT'in bir hatası var: yanılmıyorsam, ::bağlayıcı operatörü her uygulandığında yeni bir değer döndürür. Bu nedenle, olay dinleyiciniz aslında kayıtsız kalmayacaktır, çünkü sonuçlarınız removeEventListenerilk önce aktarılandan farklı bir işlev geçirir addEventListener.
natevw

21

16,8 Tepki itibariyle kullanabilirsiniz Hooks !

/* globals window */
import React, { useState, useEffect } from 'react'
import _debounce from 'lodash.debounce'

const Example = () => {
  const [width, setWidth] = useState(window.innerWidth)

  useEffect(() => {
    const handleResize = _debounce(() => setWidth(window.innerWidth), 100)

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    }
  }, [])

  return <>Width: {width}</>
}

13

Edit 2018 : Şimdi React bağlam için birinci sınıf desteğe sahip


Bu özel problemi hedefleyen genel bir cevap vermeye çalışacağım ama aynı zamanda daha genel bir problem de sunacağım.

Yan etki libs'i umursamıyorsanız, sadece Packery

Flux kullanıyorsanız, pencere nesnesini her seferinde sorgulamak zorunda kalmadan saf bir oluşturma işlevini korumak için pencere özelliklerini içeren bir mağaza oluşturabilirsiniz.

Duyarlı bir web sitesi oluşturmak istediğiniz, ancak satır içi stilleri medya sorgularına tepki vermeyi tercih ettiğiniz veya HTML / JS davranışının pencere genişliğine göre değişmesini istediğiniz diğer durumlarda, okumaya devam edin:

React bağlamı nedir ve neden bunun hakkında konuşuyorum

Reaksiyon bağlamı a, genel API'da değildir ve özelliklerin bir bileşen hiyerarşisine geçirilmesine izin verir.

React bağlamı, tüm uygulamanıza asla değişmeyen şeyleri iletmek için özellikle yararlıdır (birçok Flux çerçevesi tarafından bir mixin aracılığıyla kullanılır). Uygulama iş değişmezlerini saklamak için kullanabilirsiniz (bağlı userId gibi, her yerde kullanılabilir).

Ancak değişebilen şeyleri saklamak için de kullanılabilir. Sorun, içerik değiştiğinde, onu kullanan tüm bileşenlerin yeniden oluşturulması ve bunun kolay olmamasıdır, en iyi çözüm genellikle tüm uygulamayı yeni içerikle birlikte çıkarmak / yeniden monte etmektir. ForceUpdate'in yinelemeli olmadığını unutmayın .

Anladığınız gibi, bağlam pratiktir, ancak değiştiğinde bir performans etkisi vardır, bu yüzden çok sık değişmemelidir.

Bağlamda ne konmalı

  • Değişmezler: bağlı userId, sessionToken gibi ...
  • Sık sık değişmeyen şeyler

Sık sık değişmeyen şeyler şunlardır:

Mevcut kullanıcı dili :

Çok sık değişmez ve değiştiğinde, tüm uygulama çevrildikçe her şeyi yeniden işlemeliyiz: çok güzel sıcak langage değişimi

Pencere özellikleri

Genişlik ve yükseklik sık sık değişmemekle birlikte, yaptığımız düzen ve davranışlarımıza uyum sağlamak zorunda kalabiliriz. Düzen için bazen CSS ortam sorguları ile özelleştirmek kolaydır, ancak bazen farklı bir HTML yapısı değildir ve gerektirir. Davranış için bunu Javascript ile işlemeniz gerekir.

Her yeniden boyutlandırma etkinliğindeki her şeyi yeniden oluşturmak istemezsiniz, bu nedenle yeniden boyutlandırma etkinliklerini geri almanız gerekir.

Sorununuzu anladığım şey, ekran genişliğine göre kaç öğenin görüntüleneceğini bilmek istediğinizdir. Yani önce duyarlı kesme noktalarını tanımlamanız gerekir ve sahip olabileceğiniz farklı düzen türlerinin sayısını numaralandırmanız gerekir.

Örneğin:

  • Genişlik <= 600 için "1col" düzeni
  • Düzen "2col", 600 <genişlik <1000 için
  • 1000 <= genişlik için "3col" düzeni

Yeniden boyutlandırma olaylarında (yeniden başlatma), pencere nesnesini sorgulayarak geçerli düzen türünü kolayca alabilirsiniz.

Ardından, düzen türünü eski düzen türüyle karşılaştırabilirsiniz ve değiştiyse uygulamayı yeni bir bağlamla yeniden oluşturun: bu, kullanıcı yeniden boyutlandırma olaylarını tetiklediğinde uygulamanın yeniden oluşturulmasını önlemeye izin verir, ancak aslında mizanpaj türü değişmedi, bu nedenle yalnızca gerektiğinde yeniden oluşturursunuz.

Bunu yaptıktan sonra, HTML, davranış, CSS sınıflarını özelleştirebilmeniz için uygulamanızın içindeki düzen türünü (bağlamdan erişilebilir) kullanabilirsiniz. Böylece, React rendering işlevi içindeki düzen türünüzü bilirsiniz; satır içi stiller kullanarak duyarlı web sitelerini güvenli bir şekilde yazabilir ve medya sorgularına hiç ihtiyaç duymaz.

Flux kullanıyorsanız, React bağlamı yerine bir mağaza kullanabilirsiniz, ancak uygulamanızda çok fazla duyarlı bileşen varsa belki bağlam kullanmak daha kolay mıdır?


10

@Senornestor'un çözümünü kullanıyorum, ancak tamamen doğru olmak için olay dinleyicisini de kaldırmanız gerekiyor:

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

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

handleResize = () => {
    this.forceUpdate();
};

Aksi takdirde uyarıyı alırsınız:

Uyarı: forceUpdate (...): Yalnızca bağlı veya montajlı bir bileşeni güncelleyebilir. Bu genellikle monte edilmemiş bir bileşende forceUpdate () olarak adlandırdığınız anlamına gelir. Bu bir operasyon değil. Lütfen XXX bileşeninin kodunu kontrol edin.


1
Bir sebepten dolayı uyarı alıyorsunuz: Yaptığınız şey kötü uygulama. Render () işleviniz sahne ve durumun saf bir işlevi olmalıdır. Sizin durumunuzda, yeni boyutu eyalette kaydetmelisiniz.
zoran404

7

Yukarıdaki yanıtların tümünü atlayıp react-dimensionsYüksek Sipariş Bileşenini kullanmaya başlarım .

https://github.com/digidem/react-dimensions

Basit importve bir işlev çağrısı eklemeniz yeterlidir ve bileşeninize this.props.containerWidthve this.props.containerHeightbileşeninizden erişebilirsiniz .

// Example using ES6 syntax
import React from 'react'
import Dimensions from 'react-dimensions'

class MyComponent extends React.Component {
  render() (
    <div
      containerWidth={this.props.containerWidth}
      containerHeight={this.props.containerHeight}
    >
    </div>
  )
}

export default Dimensions()(MyComponent) // Enhanced component

1
Bu, pencerenin boyutunu değil, sadece kabı verir.
mjtamlyn

3
Evet, bütün mesele bu. Pencerenin boyutu bulmak önemsizdir. Bir kabın boyutunu bulmak çok daha zordur ve bir React bileşeni için çok daha kullanışlıdır. react-dimensionsHatta en son sürümü programlı olarak değiştirilmiş boyutlar için çalışır (örneğin, kabınızın boyutunu etkileyen bir div'ın boyutu değişti, bu nedenle boyutunuzu güncellemeniz gerekir). Ben Alpert'in yanıtı yalnızca tarayıcı penceresi yeniden boyutlandırma olaylarında yardımcı olur. Buraya bakın: github.com/digidem/react-dimensions/issues/4
MindJuice

1
react-dimensionspencerenin boyutundaki değişiklikleri, esnek kutu düzeni değişikliklerini ve JavaScript yeniden boyutlandırılmasından kaynaklanan değişiklikleri işler. Bence bunu kapsıyor. Düzgün çalışmadığı bir örneğiniz var mı?
MindJuice

2
Pencere boyutu almak önemsizdir. Bunun için bir kütüphaneye gerek yok: window.innerWidth, window.innerHeight. react-dimensionssorunun daha önemli bir kısmını çözer ve pencere yeniden boyutlandırıldığında (ayrıca konteyner boyutu değiştiğinde) düzen kodunuzu tetikler.
MindJuice

1
Bu proje artık aktif olarak sürdürülmemektedir.
Parabolord

7

Bu kod yeni React bağlam API'sını kullanıyor :

  import React, { PureComponent, createContext } from 'react';

  const { Provider, Consumer } = createContext({ width: 0, height: 0 });

  class WindowProvider extends PureComponent {
    state = this.getDimensions();

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

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

    getDimensions() {
      const w = window;
      const d = document;
      const documentElement = d.documentElement;
      const body = d.getElementsByTagName('body')[0];
      const width = w.innerWidth || documentElement.clientWidth || body.clientWidth;
      const height = w.innerHeight || documentElement.clientHeight || body.clientHeight;

      return { width, height };
    }

    updateDimensions = () => {
      this.setState(this.getDimensions());
    };

    render() {
      return <Provider value={this.state}>{this.props.children}</Provider>;
    }
  }

Daha sonra kodunuzda istediğiniz yerde şu şekilde kullanabilirsiniz:

<WindowConsumer>
  {({ width, height }) =>  //do what you want}
</WindowConsumer>

6

Yeniden oluşturmaya zorlamanız gerekmez.

Bu OP'ye yardımcı olmayabilir, ancak benim durumumda sadece tuvalimdeki (CSS ile yapamayacağınız) widthve heightnitelikleri güncellemem gerekiyordu .

Şöyle görünüyor:

import React from 'react';
import styled from 'styled-components';
import {throttle} from 'lodash';

class Canvas extends React.Component {

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

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

    resize = throttle(() => {
        this.canvas.width = this.canvas.parentNode.clientWidth;
        this.canvas.height = this.canvas.parentNode.clientHeight;
    },50)

    setRef = node => {
        this.canvas = node;
    }

    render() {
        return <canvas className={this.props.className} ref={this.setRef} />;
    }
}

export default styled(Canvas)`
   cursor: crosshair;
`

5

Bunun en iyi yaklaşım olup olmadığından emin değilim, ama benim için işe yarayan ilk önce bir Mağaza oluşturmaktı, buna WindowStore adını verdim:

import {assign, events} from '../../libs';
import Dispatcher from '../dispatcher';
import Constants from '../constants';

let CHANGE_EVENT = 'change';
let defaults = () => {
    return {
        name: 'window',
        width: undefined,
        height: undefined,
        bps: {
            1: 400,
            2: 600,
            3: 800,
            4: 1000,
            5: 1200,
            6: 1400
        }
    };
};
let save = function(object, key, value) {
    // Save within storage
    if(object) {
        object[key] = value;
    }

    // Persist to local storage
    sessionStorage[storage.name] = JSON.stringify(storage);
};
let storage;

let Store = assign({}, events.EventEmitter.prototype, {
    addChangeListener: function(callback) {
        this.on(CHANGE_EVENT, callback);
        window.addEventListener('resize', () => {
            this.updateDimensions();
            this.emitChange();
        });
    },
    emitChange: function() {
        this.emit(CHANGE_EVENT);
    },
    get: function(keys) {
        let value = storage;

        for(let key in keys) {
            value = value[keys[key]];
        }

        return value;
    },
    initialize: function() {
        // Set defaults
        storage = defaults();
        save();
        this.updateDimensions();
    },
    removeChangeListener: function(callback) {
        this.removeListener(CHANGE_EVENT, callback);
        window.removeEventListener('resize', () => {
            this.updateDimensions();
            this.emitChange();
        });
    },
    updateDimensions: function() {
        storage.width =
            window.innerWidth ||
            document.documentElement.clientWidth ||
            document.body.clientWidth;
        storage.height =
            window.innerHeight ||
            document.documentElement.clientHeight ||
            document.body.clientHeight;
        save();
    }
});

export default Store;

Sonra bu mağazayı bileşenlerimde kullandım, şöyle:

import WindowStore from '../stores/window';

let getState = () => {
    return {
        windowWidth: WindowStore.get(['width']),
        windowBps: WindowStore.get(['bps'])
    };
};

export default React.createClass(assign({}, base, {
    getInitialState: function() {
        WindowStore.initialize();

        return getState();
    },
    componentDidMount: function() {
        WindowStore.addChangeListener(this._onChange);
    },
    componentWillUnmount: function() {
        WindowStore.removeChangeListener(this._onChange);
    },
    render: function() {
        if(this.state.windowWidth < this.state.windowBps[2] - 1) {
            // do something
        }

        // return
        return something;
    },
    _onChange: function() {
        this.setState(getState());
    }
}));

Bilginize, bu dosyalar kısmen kesilmiş.


1
Mağaza durumu yalnızca gönderilen bir eyleme yanıt olarak değişmelidir. Bu kesinlikle bunu yapmanın iyi bir yolu değil.
ayaz

2
@frostymarvelous, belki de diğer cevaplarda olduğu gibi bileşene daha iyi yerleştirilmiş olabilir.
David Sinclair

@DavidSinclair Veya daha da iyisi, onresizea WindowResizedAction.
John Weisz

1
Bu aşırıya kaçmış.
Jason Rice

5

Bunun cevaplandığını biliyorum, ancak çözümümü en iyi cevap olarak paylaşacağımı düşündüm, ancak harika olsa da, şimdi biraz modası geçmiş olabilir.

    constructor (props) {
      super(props)

      this.state = { width: '0', height: '0' }

      this.initUpdateWindowDimensions = this.updateWindowDimensions.bind(this)
      this.updateWindowDimensions = debounce(this.updateWindowDimensions.bind(this), 200)
    }

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

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

    updateWindowDimensions () {
      this.setState({ width: window.innerWidth, height: window.innerHeight })
    }

Tek fark gerçekten performansı biraz artırmak için yeniden boyutlandırma olayında updateWindowDimensions (sadece her 200ms çalıştıran) debouncing olduğunu, ancak ComponentDidMount çağrıldığında onu geri değil.

Sıkışmanın, sık sık monte edildiği bir durum varsa, bazen montajı oldukça geciktirdiğini buluyordum.

Sadece küçük bir optimizasyon ama umut birisi yardımcı olur!


initUpdateWindowDimensionsYöntemin tanımı nerededir ?
Matt

Yapıcıda tanımlanmıştır :) sadece updateWindowDimensions bileşenine bağlı ancak açılma olmadan.
Matt Wills

3

Sadece @ senornestor'un çözümünü forceUpdateve @ gkri'nin resizebileşen dinleyicisindeki olay dinleyicisini kaldırma çözümünü geliştirmek için :

  1. yeniden boyutlandırma çağrısını kısıtlamayı (veya geri çekmeyi) unutmayın
  2. bind(this)yapıcıda emin olun
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 (
      <div>{window.innerWidth} x {window.innerHeight}</div>
    )
  }
}

Başka bir yöntem sadece "yapay" bir durum kullanmaktır forceUpdate:

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 (
      <div>{window.innerWidth} x {window.innerHeight}</div>
    )
  }
}

2
componentDidMount() {

    // Handle resize
    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();
};

Yalnızca resize olay işlevini tanımlamanız gerekir.

Ardından, oluşturucuların boyutunu (tuval) güncelleyin, kamera için yeni bir en boy oranı atayın.

Sökmek ve yeniden kullanmak bence çılgın bir çözüm ....

gerekirse montaj aşağıda.

            <div
                className={this.state.canvasActive ? 'canvasContainer isActive' : 'canvasContainer'}
                ref={mount => {
                    this.mount = mount;
                }}
            />

2

Kullanarak bulduğum bu güzel şeyi paylaşmak istedim window.matchMedia

const mq = window.matchMedia('(max-width: 768px)');

  useEffect(() => {
    // initial check to toggle something on or off
    toggle();

    // returns true when window is <= 768px
    mq.addListener(toggle);

    // unmount cleanup handler
    return () => mq.removeListener(toggle);
  }, []);

  // toggle something based on matchMedia event
  const toggle = () => {
    if (mq.matches) {
      // do something here
    } else {
      // do something here
    }
  };

.matches pencere belirtilen maksimum genişlik değerinden daha yüksek veya daha düşükse true veya false döndürürse, matchMedia boole değiştiğinde yalnızca bir kez tetiklendiğinden dinleyiciyi kısaltmaya gerek olmadığı anlamına gelir.

useStateKodum, boole matchMedia iadelerini kaydetmek için dahil edilecek şekilde kolayca ayarlanabilir ve bunu bir bileşeni, yangın eylemini vb.


1

Class sözdizimi ile çalışmasını sağlamak için yapıcıda 'this' bağlamak zorunda kaldı

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

1

Cevaplar için hepinize teşekkürler. İşte benim React + Yeniden Oluşturma . Bileşene windowHeightve windowWidthözelliklerini içeren bir Yüksek Sipariş İşlevidir .

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

1

https://github.com/renatorib/react-sizes , hala iyi bir performans sürdürürken bunu yapmak için bir HOC.

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

@withSizes(({ width }) => ({ isMobile: width < 480 }))
class MyComponent extends Component {
  render() {
    return <div>{this.props.isMobile ? 'Is Mobile' : 'Is Not Mobile'}</div>
  }
}

export default MyComponent

0

Bu nedenle, CSS veya JSON dosya verilerinden bu verileri ve sonra bu veriyi this.state ({width: "some value", height: "some value"}); veya duyarlı gösteri görüntüleri istiyorsanız kendi çalışmalarında geniş ekran verilerinin verilerini kullanan kod yazma

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.