React/Redux изоморфный / серверный рендеринг и медиа-запросы

Я начал создавать изоморфное приложение React / Redux на основе узла. Одним из требований проекта является "адаптивный" рендеринг конкретных компонентов на основе" мобильного "и" настольного " представления. Я реализовал действие Redux и редуктор для хранения экрана-информации о представлении пользователя (на основе медиа - запросов - "маленький", "средний", "большой") в состоянии. При изменении размера состояние / магазин обновляется. Состояние по умолчанию - "small".

const defaultState = {
    isMobile: true,
    isTablet: false,
    isDesktop: false,
    sizes: {
        small: true,
        medium: false,
        large: false,
        huge: false,
    },
};

в компоненте, который необходимо отобразить "адаптивный" в двух разных версиях, основанных на размере экрана, я просто делаю:

if (small) return variation1

if (medium) return variation2

все работает.

теперь я сталкиваюсь с двумя проблемами:

  1. мое приложение изоморфно, это означает, что разметка также отображается на стороне сервера. Сервер ничего не знает о запросах браузера и мультимедиа пользователя. Так что мое состояние по умолчанию - "маленький", сервер всегда будет отображать "variation1". Узел-сервер является точкой входа для сайта. Похоже, что рендеринг должен быть "отложен" (middleware?) и сервер должен получить некоторую информацию от клиента о ширине браузера до того, как приложение реагирует получит "доставлено". Есть идеи, как решить эту проблему?

  2. поскольку рендеринг основан на состоянии, после загрузки "Вариант 1" всегда можно увидеть сначала в течение нескольких миллисекунд (мерцание), даже когда размер браузера "рабочий стол". Это связано с тем, что обнаружение JS занимает несколько миллисекунд, прежде чем состояние обновляется с текущей шириной экрана. Я думаю, что это играет вместе с вышеуказанной проблемой и состоянием по умолчанию.

Я не мог найти решения для 1, но я думаю, что должно быть что-то изоморфное и отзывчивое/адаптивное.

2 ответов


вы можете получить агент пользователя из заголовка на сервере, а затем отправить действие redux с информацией агента пользователя с редуктором, который возвращает данные, таким образом, вы можете определить, является ли пользователь на мобильном телефоне/планшете/рабочем столе/и т. д. и соответственно


очень трудная проблема для решения, на мой взгляд, с большим количеством решений на основе" это зависит". :)

Я автор react-sizeme и react-component-queries, две библиотеки, чтобы помочь с отзывчивыми компонентами, и испытали аналогичные проблемы, о которых вы описываете в своем вопросе. По своему опыту я знаю, что решение одной из ваших проблем часто влияет на решение другой. Я подробно опишу, что я имею в виду, описывая свой опыт под...

сначала я попытался решить вашу "проблему 2":

мерцание рендеринга из-за состояния по умолчанию было то, что я испытал во время моего первоначального создания react-sizeme библиотека. react-sizeme - компонент более высокого порядка, который получает размер, доступный вашему компоненту, а затем передает его в ваш компонент. В зависимости от размера вы можете, конечно, выбрать визуализацию различных компонентов, как это было сделано в вашем примере, поэтому мерцание обновления может происходят, если вы случайно не попали в сладкое пятно состояния по умолчанию. Я" победил " это, изменив react-sizeme для первоначального отображения пустого заполнителя, чтобы получить доступную ширину/высоту, а затем только визуализировать ваш компонент, давая ему "правильную" ширину / высоту. Это сработало очень эффективно для меня. Я больше не вижу, как componentbob визуализируется, только чтобы быть размонтированным и иметь ComponentFoo немедленно визуализировать на его месте.

затем появилась "проблема 1" вдоль...

react-sizeme начал набирать популярность, и в конце концов у меня был потребитель библиотеки, который хотел использовать его в контексте рендеринга на стороне сервера. Но из-за исправления, которое я поставил для проблемы 1, рендеринг на стороне сервера будет производить много пустого контента (т. е. заполнителей, о которых я говорил). После того, как полезная нагрузка была доставлена в браузер, логика заполнителя сработает, и в конечном итоге данные размера будут отправлены компоненту, и это будет оказанный. Это не идеально, так как вы в первую очередь сводите на нет любое преимущество SSR. Я работал с этим пользователем, и мы решили, что было бы лучше, чтобы для react-sizeme быть настроенным для работы в"режиме SSR". В основном это повлекло за собой удаление отрисовки заполнителя и разрешение отрисовки компонента по умолчанию, чтобы вы не получали пустые страницы в исходном ответе сервера, но тогда вы можете легко пострадать от проблемы мерцания компонента опять!

Aaaaaaaaaah! The see saw of affect here! :(

таким образом, в основном решение одной проблемы напрямую влияет на другую.


я продолжал думать об этом, и я считаю, что, вероятно, лучший способ сделать это-попытаться получить ширину/высоту браузера пользователей по первому запросу. Это по существу означало бы рендеринг простой утилиты, которая выуживает эту информацию, а затем отправляет ее обратно на сервер с целью рендеринга первоначальный запрос пользователя. Затем вы можете использовать ширину/высоту и передать ее через все дерево компонентов (выполняя математику по пути), чтобы продолжить определение доступной высоты / ширины для каждого компонента. Здесь все очень сложно, но может сработать.

другая опасность, конечно, заключается в том, что google просто индексирует пустую страницу для первоначального запроса (т. е. пустой рендеринг util, который выуживает начальную ширину/высоту). Вы должны попробовать и посмотреть в использовании некоторые умные коды ответа HTTP, такие как перенаправления и т. д., чтобы гарантировать, что google следует по следу к правильному отображаемому выходу.


извините, это может быть не тот ответ, который вы искали, но, надеюсь, мой опыт помогает каким-то образом или дает какое-то вдохновение. Если вы придумаете интересные эксперименты, пожалуйста, держите меня в курсе. Я был бы рад поработать с вами над этим.