简体   繁体   English

React / Redux同构/服务器端呈现和媒体查询

[英]React/Redux isomorphic / server-side rendering and media queries

I started creating an isomorphic React/Redux app based on Node. 我开始创建一个基于Node的同构React / Redux应用程序。 One requirement of the project is "adapative" rendering of specific components based on a "mobile" and "desktop" view. 该项目的一个要求是基于“移动”和“桌面”视图的“适应性”呈现特定组件。 I have implemented Redux action and reducer to store screen-information about the user's view (based on media queries - "small", "medium", "large") in the state. 我已经实现了Redux动作和reducer来存储有关用户视图的屏幕信息(基于媒体查询 - “小”,“中”,“大”)。 On resize the state/store gets updated. 在调整大小时,状态/商店会更新。 The default state is "small". 默认状态为“小”。

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

In the component which needs to be rendered "adaptive" in two different versions based on the screen size, I simply do a: 在需要根据屏幕大小在两个不同版本中呈现“自适应”的组件中,我只需执行以下操作:

if (small) return variation1 如果(小)返回变化1

if (medium) return variation2 如果(中)返回变异2

All working. 一切正常。

Now I am facing two problems: 现在我面临两个问题:

  1. my app is isomorphic, that means the markup renders also server-side. 我的应用程序是同构的,这意味着标记也呈现服务器端。 The server doesn't know anything about the user's browser and media queries. 服务器对用户的浏览器和媒体查询一无所知。 So because my default state is "small", the server will always render "variation1". 因为我的默认状态是“小”,服务器将始终呈现“variation1”。 The node-server is the entry point for the site. 节点服务器是站点的入口点。 It looks like the rendering needs to be "delayed" (middleware?) and the server needs to get some information back from the client about the browser width before the React app gets "delivered". 看起来渲染需要“延迟”(中间件?),服务器需要在React应用程序“交付”之前从客户端获取有关浏览器宽度的一些信息。 Any idea how this problem can be solved? 知道如何解决这个问题吗?

  2. because the rendering is based on the state, after load "variation 1" can be always seen first for a few milliseconds (flicker), even when the browser size is "desktop". 因为渲染是基于状态的,所以在加载“变化1”之后总是可以看到几毫秒(闪烁),即使浏览器大小是“桌面”。 This is because the JS detection takes a few milliseconds before the state gets updated with the current screen width. 这是因为在使用当前屏幕宽度更新状态之前,JS检测需要几毫秒。 I think this plays together with above problem and the default state. 我认为这与上述问题和默认状态一起发挥作用。

I couldn't find any solution for 1, but I guess there must be something isomorphic AND responsive/adaptive. 我找不到1的任何解决方案,但我想必须有一些同构和响应/自适应的东西。

A very difficult problem to solve in my opinion with a lot of "it depends" based solutions. 在我看来,一个非常难以解决的问题是基于很多“依赖于”的解决方案。 :) :)

I am the author of react-sizeme and react-component-queries , two libraries to help with responsive components, and have experienced similar problems as to which you describe in your question. 我是react-sizemereact-component-queries ,两个库来帮助响应组件,并且遇到了与您在问题中描述的类似问题。 In my experience I've found that coming up with a solution to one of your problems often affects the other. 根据我的经验,我发现解决你的一个问题通常会影响另一个问题。 I'll detail what I mean here by describing my experience below... 我将通过描述下面的经验详细说明我的意思......

I had tried to solve your "problem 2" first: 我曾尝试先解决你的“问题2”:

The flickering of rendering due to the default state was something I experienced during my initial creation of the react-sizeme library. 由于默认状态导致的渲染闪烁是我在初始创建react-sizeme库时react-sizeme react-sizeme is a higher order component which gets the size available to your component and then passes it into your component. react-sizeme是一个更高阶的组件,它获取组件可用的大小,然后将其传递给组件。 Based on the size you can of course choose to render different components as you have done in your example, so update flickering can occur unless you happen to hit a default state sweet spot. 基于大小,您当然可以选择渲染不同的组件,就像您在示例中所做的那样,因此除非您碰巧遇到默认状态最佳位置,否则可能会发生更新闪烁。 I "conquered" this by changing react-sizeme to initially render an empty placeholder in order to get the available width/height and then only render your Component, giving it the "proper" width/height. 我通过改变react-sizeme来“征服”这react-sizeme ,最初渲染一个空占位符以获得可用的宽度/高度,然后只渲染你的Component,给它“适当的”宽度/高度。 This has worked very effectively for me. 这对我来说非常有效。 No longer do I see ComponentBob being rendered, only to be unmounted and have ComponentFoo immediately render in it's place. 我不再看到ComponentBob被渲染,只是被卸载并让ComponentFoo立即渲染到它的位置。

Then "problem 1" came along... 然后“问题1”出现了......

react-sizeme started to gain popularity and eventually I had a consumer of the library who wished to use it in a server side rendering context. react-sizeme开始流行起来,最终我有一个图书馆的消费者希望在服务器端渲染环境中使用它。 But because of the fix I put in place for problem 1 the server side rendering would produce a lot of blank content (ie the placeholders I was talking about). 但是由于我为问题1设置的修复,服务器端渲染会产生大量空白内容(即我正在谈论的占位符)。 After the payload was delivered to the browser the placeholder logic would kick in and eventually the size data would be sent to the component and it would be rendered. 在将有效负载传递到浏览器之后,占位符逻辑将启动并最终将大小数据发送到组件并将其呈现。 This is not ideal as you essentially nullify any benefit of doing SSR in the first place. 这并不理想,因为您首先要从根本上取消做SSR的任何好处。 I worked with this user and we decided that the best way forward would be to allow for react-sizeme to be configured to run in "SSR Mode". 我与这个用户合作,我们认为最好的方法是允许将react-sizeme配置为在“SSR模式”下运行。 Basically this entailed dropping the placeholder rendering and allowing for a default Component to be rendered so that you don't get blank pages on the initial server response, but then you can easily suffer the component flickering problem again! 基本上这需要删除占位符呈现并允许呈现默认组件,以便您不会在初始服务器响应上获得空白页,但随后您可以轻松地再次遇到组件闪烁问题!

Aaaaaaaaaah! Aaaaaaaaaah! The see saw of affect here! 在这里看见了影响! :( :(

So basically solving one problem directly affects the other. 所以基本上解决一个问题直接影响另一个。


I've continued to give this some thought and I believe that probably the best way to do this is to try and get the users browser width/height on first request. 我继续给出一些想法,我相信最好的方法是尝试在第一次请求时获取用户浏览器的宽度/高度。 This would essentially mean rendering a simple utility that fishes out this information and then posts it back to the server with the intention of rendering the user's initial request. 这实际上意味着渲染一个简单的实用程序,它可以捕获此信息,然后将其发回服务器,以便呈现用户的初始请求。 You could then use the width/height and pass it through your entire component tree (doing math along the way) to keep on determining what the available height/width is for each component. 然后,您可以使用宽度/高度并将其传递到整个组件树(沿途进行数学运算),以继续确定每个组件的可用高度/宽度。 Super tricky stuff here, but could possibly work. 这里有超级棘手的东西,但可能会奏效。

The other peril of course is that google simply indexes a blank page for the initial request (ie the blank render of the util that fishes out the initial width/height). 另一个危险当然是google只是为初始请求索引一个空白页面(即用于捕获初始宽度/高度的util的空白渲染)。 You would have to try and look into using some clever HTTP Response codes such as redirects etc in order to ensure that google follows the trail to the proper rendered output. 你必须尝试使用​​一些聪明的HTTP响应代码,如重定向等,以确保谷歌跟踪到正确的渲染输出。


Sorry, this may not be the answer you were looking for, but hopefully my experience helps in some manner or provides some sort of inspiration. 对不起,这可能不是您正在寻找的答案,但希望我的经验有所帮助或提供某种灵感。 If you do come up with some interesting experiments please do keep me posted. 如果您确实想出了一些有趣的实验,请让我发布。 I would be happy to work with you on this. 我很乐意和你一起工作。

您可以从服务器上的标头获取用户代理,然后使用返回数据的reducer发送带有用户代理信息的redux操作,这样您就可以检测用户是否在手机/平板电脑/桌面/等等上进行相应的渲染

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM