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