Как я могу заставить React повторно визуализировать представление при изменении размера окна браузера?
Задний план
У меня есть несколько блоков, которые я хочу разместить на странице по отдельности, но я также хочу, чтобы они обновлялись при изменении окна браузера. Самым конечным результатом будет что-то вроде макета Бена Холланда на Pinterest, но написанное с использованием 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
});
Есть ли более «реактивный» способ сделать это?
источник
this.updateDimensions
ПередаютсяaddEventListener
только голая ссылка на функцию , которая не будет иметь никакого значения дляthis
при вызове. Следует ли использовать анонимную функцию или вызов .bind () для добавленияthis
, или я неправильно понял?this
любые методы, определенные непосредственно в компоненте.innerHeight
иinnerWidth
отwindow
. И вы можете пропустить,componentWillMount
если вы используетеgetInitialState
для установкиheight
иwidth
.::
синтаксис привязки выходит на текущий sitepoint.com/bind-javascripts-this-keyword-react «оператор связывания (: :) не собирается быть частью ES7, в особенности ES7 набор был заморожен в феврале , оператор связывания - это предложение для ES8 "@SophieAlpert права, +1, я просто хочу предоставить модифицированную версию ее решения без jQuery , основываясь на этом ответе .
источник
Очень простое решение:
источник
componentWillUnmount()
!forceUpdate
это применяется условноЭто простой и короткий пример использования es6 без jQuery.
крючки
источник
::
оператор связывания возвращает новое значение каждый раз, когда оно применяется. Таким образом, ваш прослушиватель событий не будет фактически незарегистрированным, так как вremoveEventListener
итоге вы передадите функцию, отличную от той, которая была первоначально переданаaddEventListener
.Начиная с React 16.8 вы можете использовать крючки !
источник
Edit 2018 : теперь React имеет первоклассную поддержку контекста
Я постараюсь дать общий ответ, который нацелен на эту конкретную проблему, но также и на более общую проблему.
Если вам не нужны побочные эффекты, вы можете просто использовать что-то вроде Packery
Если вы используете Flux, вы можете создать хранилище, содержащее свойства окна, чтобы вы сохраняли чистую функцию рендеринга без необходимости каждый раз запрашивать объект окна.
В других случаях, когда вы хотите создать адаптивный веб-сайт, но предпочитаете встроенные стили React медиазапросам или хотите, чтобы поведение HTML / JS изменялось в зависимости от ширины окна, продолжайте читать:
Что такое контекст React и почему я об этом говорю
Реагирующий контекст an не находится в общедоступном API и позволяет передавать свойства всей иерархии компонентов.
Контекст React особенно полезен для передачи всему вашему приложению того, что никогда не меняется (его используют многие фреймворки Flux через миксин). Вы можете использовать его для хранения бизнес-инвариантов приложения (например, подключенного userId, чтобы он был доступен везде).
Но его также можно использовать для хранения вещей, которые могут измениться. Проблема заключается в том, что при изменении контекста все компоненты, которые его используют, должны быть перерисованы, и это нелегко сделать, лучшее решение часто состоит в том, чтобы размонтировать / перемонтировать все приложение с новым контекстом. Помните, что forceUpdate не является рекурсивным .
Итак, как вы понимаете, контекст практичен, но когда он меняется, он влияет на производительность, поэтому не следует менять его слишком часто.
Что поместить в контекст
Вот вещи, которые не часто меняются:
Текущий язык пользователя :
Это не очень часто меняется, и когда это происходит, когда переводится все приложение, мы должны перерисовывать все: очень хороший пример использования горячих изменений языка.
Свойства окна
Ширина и высота меняются не часто, но когда мы делаем наш макет и поведение, возможно, придется адаптироваться. Для макета иногда легко настроить с помощью медиазапросов CSS, но иногда это не так и требует другой структуры HTML. Для поведения вы должны справиться с этим с помощью Javascript.
Вы не хотите перерисовывать все при каждом событии изменения размера, поэтому вам нужно отменить изменения размера события.
Что я понимаю в вашей проблеме, так это то, что вы хотите знать, сколько элементов отображается в зависимости от ширины экрана. Итак, вы должны сначала определить отзывчивые точки останова и перечислить количество различных типов макетов, которые вы можете иметь.
Например:
По событиям изменения размера (опровергнутым) вы можете легко получить текущий тип макета, запросив объект окна.
Затем вы можете сравнить тип макета с прежним типом макета и, если он изменился, повторно выполнить рендеринг приложения с новым контекстом: это позволяет избежать повторного рендеринга приложения вообще, когда пользователь имеет триггерные события изменения размера, но на самом деле Тип макета не изменился, поэтому вы можете выполнить повторную визуализацию только при необходимости.
Как только вы это сделаете, вы можете просто использовать тип макета внутри вашего приложения (доступный через контекст), чтобы вы могли настроить HTML, поведение, классы CSS ... Вы знаете свой тип макета внутри функции рендеринга React, так что это означает, что вы может безопасно писать адаптивные веб-сайты, используя встроенные стили, и вообще не нуждается в медиазапросах.
Если вы используете Flux, вы можете использовать хранилище вместо контекста React, но если в вашем приложении много отзывчивых компонентов, может быть, проще использовать контекст?
источник
Я использую решение @senornestor, но, чтобы быть полностью правильным, вы также должны удалить прослушиватель событий:
В противном случае вы получите предупреждение:
источник
Я бы пропустил все приведенные выше ответы и начал бы использовать
react-dimensions
компонент высшего порядка.https://github.com/digidem/react-dimensions
Просто добавьте простой
import
и функциональный вызов, и вы сможете получить доступthis.props.containerWidth
иthis.props.containerHeight
к своему компоненту.источник
react-dimensions
даже работает для программно измененных размеров (например, изменился размер элемента div, который влияет на размер вашего контейнера, поэтому вам необходимо обновить свой размер). Ответ Бена Альперта помогает только при изменении размера окна браузера. Смотрите здесь: github.com/digidem/react-dimensions/issues/4react-dimensions
обрабатывает изменения размера окна, изменения макета flexbox и изменения из-за изменения размера JavaScript. Я думаю, что это охватывает. У вас есть пример, что он не справляется должным образом?window.innerWidth
,window.innerHeight
.react-dimensions
решает более важную часть проблемы, а также запускает код макета при изменении размера окна (а также при изменении размера контейнера).Этот код использует новый контекстный API React :
Затем вы можете использовать его где угодно в своем коде, например так:
источник
Вам не обязательно форсировать повторную визуализацию.
Это не может помочь О.П., но в моем случае я только нужно обновить
width
иheight
атрибуты на моем холсте (которые вы не можете сделать с помощью CSS).Это выглядит так:
источник
Не уверен, что это лучший подход, но для меня сначала было создать Магазин, я назвал его WindowStore:
Затем я использовал этот магазин в своих компонентах, вроде этого:
К вашему сведению, эти файлы были частично обрезаны.
источник
onresize
может отправитьWindowResizedAction
.Я знаю, что на этот вопрос уже был дан ответ, но подумал, что поделюсь своим решением, так как лучший ответ, хотя и отличный, может теперь немного устареть.
Единственное отличие на самом деле в том, что я отменяю (только каждые 200 мс) updateWindowDimensions для события resize, чтобы немного повысить производительность, НО не отменяю его при вызове в ComponentDidMount.
Я обнаружил, что отскок сделал его довольно запоздалым, если он часто монтируется.
Просто небольшая оптимизация, но надеюсь, она кому-нибудь поможет!
источник
initUpdateWindowDimensions
метода?Просто чтобы улучшить решение @ senornestor для использования
forceUpdate
и решение @ gkri для удаленияresize
прослушивателя событий на компоненте unmount:bind(this)
в конструктореДругой метод - просто использовать "фиктивное" состояние вместо
forceUpdate
:источник
Нужно только определить функцию изменения размера события.
Затем обновите размер рендера (холст), назначьте новое соотношение сторон для камеры.
Размонтирование и перенастройка - сумасшедшее решение, на мой взгляд ....
ниже крепление при необходимости.
источник
Хотел поделиться этой довольно классной вещью, которую я только что нашел, используя
window.matchMedia
.matches
вернет true или false, если окно больше или меньше указанного значения max-width, это означает, что нет необходимости регулировать слушателя, так как matchMedia запускается только один раз, когда изменяется логическое значение.Мой код можно легко настроить, чтобы включить
useState
для сохранения логических возвращений matchMedia и использовать его для условной визуализации компонента, действия при пожаре и т. Д.источник
Пришлось связать его с этим в конструкторе, чтобы он работал с синтаксисом класса
источник
Спасибо всем за ответы. Вот мой Реакт + Рекомендовать . Это функция высокого порядка, которая включает в себя
windowHeight
иwindowWidth
свойства компонента.источник
https://github.com/renatorib/react-sizes - это HOC, который делает это, сохраняя при этом хорошую производительность.
источник
По этой причине лучше, если вы используете эти данные из данных файла CSS или JSON, а затем с этими данными устанавливаете новое состояние с помощью this.state ({width: "some value", height: "some value"}); или написание кода, который использует данные ширины экрана в самостоятельной работе, если вы хотите, чтобы изображения показывались быстро
источник