Перегляд рендерингу розміру браузера за допомогою React


313

Як я можу змусити React відновити перегляд, коли розмір вікна браузера буде змінено?

Фон

У мене є кілька блоків, які я хочу розміщувати окремо на сторінці, однак я також хочу, щоб вони оновлювалися, коли змінюється вікно браузера. Самим кінцевим результатом буде щось на зразок макета Pinterest Ben Holland , але написане за допомогою React, а не лише jQuery. Я все-таки вихід.

Код

Ось моя програма:

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

Тоді у мене є Blockкомпонент (еквівалентний а Pinв наведеному вище прикладі Pinterest):

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

і список / колекція 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>
    );
  }
});

Питання

Чи слід додати розмір вікна jQuery? Якщо так, то де?

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

Чи існує більш "реагувати" спосіб цього?

Відповіді:


531

Використання React Hooks:

Ви можете визначити спеціальний гачок, який прослуховує resizeподію вікна , приблизно так:

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

Перевага тут полягає в тому, що логіка інкапсульована, і ви можете використовувати цей гачок у будь-якому місці, де ви хочете використовувати розмір вікна.

Використання класів React:

Ви можете слухати в компонентDidMount, щось подібне до цього компонента, який просто відображає розміри вікна (як <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);
  }
}

5
Як це працює? this.updateDimensionsПередаються addEventListenerтільки гола посилання на функцію , яка не матиме ніякого значення для thisвиклику. Чи слід використовувати анонімну функцію або виклик .bind () для додавання thisчи я неправильно зрозумів?
fadedbee

24
@chrisdew Я трохи запізнююсь тут, але React автоматично зв'язує thisбудь-які методи, визначені безпосередньо на компоненті.
Мішель Тіллі

3
@MattDell так, класи ES6 - це просто звичайні класи, тому ніякого автоматичного зв’язування з ними немає.
Мішель Тіллі

30
Не потрібно jQuery - використовувати innerHeightта innerWidthз window. І ви можете пропустити, componentWillMountякщо ви getInitialStateвстановите heightі width.
sighrobot

2
@MattDell виглядає так, що ::синтаксис прив’язки наразі вийшов на сайт sitepoint.com/bind-javascripts-this-keyword-react "оператор зв'язування (: :) не буде частиною ES7, оскільки набір функцій ES7 був заморожений у лютому , оператор прив’язки - це пропозиція для ES8 "
Jarrod Smith

130

@SophieAlpert правий, +1, я просто хочу надати модифіковану версію її рішення, без jQuery , грунтуючись на цій відповіді .

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

працює лише тоді, коли у вас є поліфіли, пов’язані з IE, створені для слухачів подій ванілі JS
nnnn

@nnnn ви можете розробити? Признаюсь, я перевірив це лише в Chrome. Ви кажете, що window.addEventListener не буде працювати на IE без поліфілів?
Андре Пена

2
@andrerpena caniuse.com/#search=addeventlistener вказує ie8 матиме проблеми
нннн

2
@nnnn. Розумію. Так .. Отже, моє рішення не працює на IE 8, але працює з 9 по :). Дякую.
Андре Пена

35
Хтось насправді все ще хвилює IE8? Або це просто звичка?
frostymarvelous

48

Дуже просте рішення:

resize = () => this.forceUpdate()

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

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

12
Не забудьте придушити оновлення сили, інакше це буде виглядати дуже глючно.
k2snowman69

4
Також не забудьте видалити слухача componentWillUnmount()!
Джемар Джонс

Це найкращі рішення, якщо воно заглушене. Я маю на увазі, якщо forceUpdateзастосовується умовно
asmmahmud

1
ForceUpdate (те, що називається) не потрібно придушувати, це запуск події зміни розміру, який потрібно придушити (річ стріляє). Події зміни розміру технічно можна викликати на кожному пікселі, коли ви змінюєте розмір вікна від великого до малого. Коли користувач робить це швидко, це більше подій, ніж вас хвилює. Гірше, що ви прив'язуєте потік інтерфейсу користувача до потоку Javascript, тобто ваш додаток почне отримувати серйозне повільне відчуття, коли він намагається обробляти кожну подію окремо.
k2snowman69

1
Замість того, щоб запускати функцію зміни розміру на кожному пікселі, ви запускаєте її за деякий короткий проміжок часу, щоб створити ілюзію текучості, з якою ви завжди обробляєте першу та останню подію, тим самим даючи відчуття, що вона безперебійно обробляє розмір.
k2snowman69

42

Це простий і короткий приклад використання es6 без 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 (
      <span>
        {this.state.windowWidth} x {this.state.windowHeight}
      </span>
    );
  }
}

гачки

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
Це хороша, лаконічна відповідь, але AFAICT має одну помилку: якщо я не помиляюся, ::оператор прив'язки повертає нове значення кожного разу, коли воно застосовується. Тож слухач вашої події насправді не стане незареєстрованим, оскільки ваш removeEventListenerкінець переходить до іншої функції, ніж те, що було передано спочатку addEventListener.
natevw

21

Станом на React 16.8 ви можете використовувати Гачки !

/* 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

Редагувати 2018 : зараз React має першокласну підтримку контексту


Я спробую дати загальну відповідь, яка спрямована на цю конкретну проблему, але і більш загальну проблему.

Якщо вас не хвилюють побічні ефекти, але ви можете просто використовувати щось на зразок Packery

Якщо ви використовуєте Flux, ви можете створити сховище, яке містить властивості вікна, щоб зберегти чисту функцію візуалізації, не вимагаючи кожного разу запитувати віконний об’єкт.

В інших випадках, коли ви хочете створити чуйний веб-сайт, але ви віддаєте перевагу стилі вбудованого реагування на медіа-запити або хочете, щоб поведінка HTML / JS змінювалася відповідно до ширини вікна, продовжуйте читати:

Що таке контекст React і чому я про це говорю

Реагувати контекст a не в загальнодоступному API і дозволяє передавати властивості цілій ієрархії компонентів.

Контекст React особливо корисний для передачі у всій програмі речей, які ніколи не змінюються (він використовується багатьма флюкс-схемами через міксин). Ви можете використовувати його для зберігання інваріантів бізнес-додатків (наприклад, підключений користувальницький ідентифікатор, щоб він був доступний скрізь).

Але його також можна використовувати для зберігання речей, які можуть змінюватися. Проблема полягає в тому, що коли контекст змінюється, всі компоненти, які його використовують, повинні бути рендерировані, і це зробити непросто, найкращим рішенням часто є демонтування / повторне повторне перетворення цілого додатка на новий контекст. Пам'ятайте, що forceUpdate не є рекурсивним .

Отже, як ви розумієте, контекст практичний, але на його ефективність впливає його зміна, тому він не повинен змінюватися занадто часто.

Що поставити в контексті

  • Інваріанти: як підключений userId, sessionToken, що завгодно ...
  • Речі, які не змінюються часто

Ось речі, які часто не змінюються:

Поточна мова користувача :

Це не змінюється дуже часто, і коли це відбувається, як перекладено всю програму, ми повинні переробити все: дуже приємна зміна шаф із гарячим багажем

Властивості вікна

Ширина і висота не часто змінюються, але коли ми робимо наш макет і поведінку, можливо, доведеться адаптуватися. Для компонування іноді легко налаштувати CSS-медіа-запити, але іноді це не так і вимагає іншої структури HTML. Для поведінки вам доведеться це обробляти за допомогою Javascript.

Ви не хочете рендерингувати все на кожній події розміру, тому вам доведеться знімати події зміни розміру.

Що я розумію у вашій проблемі, це те, що ви хочете знати, скільки предметів відображатиметься відповідно до ширини екрана. Таким чином, ви повинні спочатку визначити чутливі точки перерви та перерахувати кількість різних типів компонування, які ви можете мати.

Наприклад:

  • Макет «1кол», для ширини <= 600
  • Макет "2col", для 600 <ширина <1000
  • Макет "3col", на 1000 <= ширина

У подіях зміни розміру (деблокується) ви можете легко отримати поточний тип макета, запитуючи об’єкт вікна.

Тоді ви можете порівняти тип макета з колишнім типом макета, і якщо він змінився, відтворіть додаток з новим контекстом: це дозволяє уникнути повторного надання додатку взагалі, коли користувач викликає події зміни розміру, але насправді тип макета не змінився, тому ви повторно візуалізуєте лише за потреби.

Після цього ви можете просто використовувати тип макета у вашій програмі (доступний через контекст), щоб ви могли налаштувати HTML, поведінку, класи CSS ... Ви знаєте тип свого макета у функції візуалізації React, тому це означає, що ви Ви можете безпечно писати чуйні веб-сайти, використовуючи стилі вбудованого характеру, і взагалі не потребують медіазапитів

Якщо ви використовуєте Flux, ви можете використовувати магазин замість React контексту, але якщо у вашому додатку багато чуйних компонентів, можливо, простіше використовувати контекст?


10

Я використовую рішення @senornestor, але щоб бути повністю коректним, потрібно також видалити слухача подій:

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

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

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

Інакше ви отримаєте попередження:

Попередження: forceUpdate (...): Оновити лише змонтований або монтажний компонент. Зазвичай це означає, що ви викликали forceUpdate () для відключеного компонента. Це не-оп. Перевірте код для компонента XXX.


1
Ви отримуєте попередження з причини: те, що ви робите, - це погана практика. Ваша функція render () повинна бути чистою функцією реквізиту та стану. У вашому випадку слід зберегти новий розмір у державі.
zoran404

7

Я пропустив би всі вищевказані відповіді і почав би використовувати react-dimensionsкомпонент Вищого порядку.

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

Просто додайте простий importі функціональний дзвінок, і ви можете отримати доступ this.props.containerWidthі this.props.containerHeightдо свого компонента.

// 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
Це не дає розміру вікна, просто контейнера.
mjtamlyn

3
Так, у цьому вся суть. Розмір вікна - тривіально знайти. Розмір контейнера набагато важче знайти та набагато корисніше для компонента React. Остання версія react-dimensionsнавіть працює для програмно змінених розмірів (наприклад, розмір div змінився, що впливає на розмір контейнера, тому вам потрібно оновити розмір). Відповідь Бен Альперта допомагає лише щодо зміни розміру подій у вікні браузера. Дивіться тут: github.com/digidem/react-dimensions/isissue/4
MindJuice

1
react-dimensionsобробляє зміни розміру вікна, змінюється макет flexbox і змінюється завдяки зміні розміру JavaScript. Я думаю, що це охоплює. Чи є у вас приклад, що він не працює належним чином?
MindJuice

2
Розмір вікна отримати тривіально. Немає необхідності в бібліотеці , що: window.innerWidth, window.innerHeight. react-dimensionsвирішує більш важливу частину проблеми, а також запускає код вашого макета, коли розмір вікна змінюється (а також коли змінюється розмір контейнера).
MindJuice

1
Цей проект більше не підтримується активно.
Параболорд

7

Цей код використовує новий контекстний API React :

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

Тоді ви можете використовувати його куди завгодно у своєму коді так:

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

6

Вам не обов’язково потрібно змушувати повторне відтворення.

Це може не допомогти OP, але в моєму випадку мені потрібно було лише оновити widthта heightатрибути на моєму полотні (що не можна зробити з CSS).

Це виглядає приблизно так:

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

Не впевнений, що це найкращий підхід, але те, що для мене спрацювало спочатку створення магазину, я назвав його WindowStore:

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;

Тоді я використовував цей магазин у своїх компонентах, таким чином:

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

Файли, ці файли були частково оброблені.


1
Стан магазину має змінюватися лише у відповідь на відправлену дію. Це, безумовно, не гарний спосіб зробити це.
frostymarvelous

2
@frostymarvelous дійсно, можливо, краще переїхати в компонент, як в інших відповідях.
Девід Сінклер

@DavidSinclair Або ще краще, onresizeможе відправити WindowResizedAction.
Джон Вейс

1
Це надмірність.
Джейсон Райс,

5

Я знаю, що на це відповіли, але я просто подумав, що поділяю своє рішення як головну відповідь, хоча це чудово, але зараз може бути трохи застарілим.

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

Єдина відмінність полягає в тому, що я денонсую (виконуючи лише кожні 200 мс) updateWindowDimensions на подію зміни розміру, щоб трохи збільшити продуктивність, але НЕ знімати його, коли він викликається на ComponentDidMount.

Я виявив, що дебюнс робив його досить млявим іноді, якщо у вас є ситуація, коли він встановлюється часто.

Просто незначна оптимізація, але сподіваюся, що вона комусь допоможе!


Де визначення initUpdateWindowDimensionsметоду?
Мет

Це визначено в конструкторі :) це просто updateWindowDimensions, прив'язані до компонента, але без дебютації.
Метт Уіллс

3

Просто для вдосконалення рішення @ senornestor, щоб використовувати forceUpdateта рішення @ gkri для видалення resizeслухача події на компоненті відключити:

  1. не забудьте придушити (або дебютувати) заклик змінити розмір
  2. переконайтеся, що bind(this)в конструкторі
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>
    )
  }
}

Інший метод - просто використовувати "фіктивний" стан замість 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();
};

Потрібно лише визначити функцію події зміни розміру.

Потім оновіть розмір візуалізації (полотно), призначте нове співвідношення сторін для камери.

Демонтування та перерахунок - на мою думку, шалене рішення ...

внизу - кріплення, якщо потрібно.

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

2

Хотів поділитися цією цікавою річчю, яку я щойно знайшов 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 повернеться true або false, якщо вікно вище або нижче вказаного значення максимальної ширини, це означає, що немає потреби заглушувати слухача, оскільки matchMedia запускається лише один раз, коли булева зміна.

Мій код можна легко налаштувати, щоб він включав useStateдля збереження булевих результатів matchMedia та використовував його для умовного візуалізації компонента, вогневих дій тощо.


1

Довелося прив’язати це до 'цього' у конструкторі, щоб він працював із синтаксисом Class

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

Дякую всім за відповіді. Ось мій React + перекомпонуйте . Це функція високого замовлення, яка включає в себе windowHeightі windowWidthвластивості компонента.

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 - це ГОС, щоб зробити це, зберігаючи при цьому хороші показники.

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

З цієї причини краще, якщо ви використовуєте ці дані з даних файлів CSS або JSON, а потім за допомогою цих даних встановіть новий стан з this.state ({width: "деяке значення", висота: "деяке значення"}); або написання коду, який використовує дані ширинного екрану для самостійної роботи, якщо ви бажаєте чуйних зображень

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.