【问题标题】:Meteor, server-render withTracker. Postponing client-renderingMeteor,服务器渲染 withTracker。推迟客户端渲染
【发布时间】:2018-07-12 01:32:43
【问题描述】:

在我的数据库中,我有一组动物,我想将它们渲染成一个漂亮的小列表。为了改善用户体验,我想在服务器上渲染它(使用新的server-render 包),然后使用react-meteor-data (withTracker) 订阅任何更改。

现在,除了一件事之外,这正在工作。服务器按预期呈现内容(包括数据),然后将其发送到客户端。问题出在客户端。

页面加载后,meteor 建立数据连接,然后呈现页面。第一次渲染发生在数据连接返回任何数据之前,因此它渲染了一个空的动物列表(覆盖服务器上渲染的列表并导致警告)。然后,一旦数据到达,列表就会完全(重新)呈现。

这会导致非常糟糕的用户体验,因为列表会闪烁然后返回。我想推迟客户端渲染,直到数据可用。这可能吗?

我的代码很简单,看起来像这样:

列表组件:

import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';

import { AnimalsData } from '../api/animals';

class Animals extends Component {
    render() {
        const {animals} = this.props;
        console.log(animals);

        return <ul>
            {animals.map(animal =>
                <li key={animal._id}>
                    {animal.name}
                </li>)
            }
        </ul>
    }
};

// Load data into props, subscribe to changes on the client
export default withTracker(params => {
    if (Meteor.isClient) {
        // No need to subscribe on server (this would cause an error)
        Meteor.subscribe('animals');
    }

    return {
        animals: AnimalsData.find({}).fetch()
    };
})(Animals);

服务器:

import React from "react";
import { renderToString } from "react-dom/server";
import { onPageLoad } from "meteor/server-render";

import Animals from '../imports/ui/Animals';
import '../imports/api/animals';

onPageLoad((sink) => {
    sink.renderIntoElementById('app', renderToString(<Animals />));
});

客户:

import React from 'react';
import ReactDOM from "react-dom";
import { onPageLoad } from "meteor/server-render";

import AnimalList from '../imports/ui/Animals';

onPageLoad(sink => {
    ReactDOM.hydrate(
        <AnimalList />,
        document.getElementById("app")
    );
});

数据库:

import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';

export const AnimalsData = new Mongo.Collection('animals');

if (Meteor.isServer) {

    Meteor.publish('animals', () => {
        return AnimalsData.find({});
    });
}

会发生什么(Animals.jsx 中的console.log):

  1. 在服务器上渲染 [动物数据]
  2. 在数据到达之前在客户端呈现。这将删除服务器上呈现的列表 []
  3. 数据到达时在客户端呈现 [动物数据]

【问题讨论】:

标签: meteor server-rendering


【解决方案1】:

您可以延迟为您的页面补充水分,直到您的订阅准备就绪。

例如,假设您有一个链接集合

import { Mongo } from 'meteor/mongo';
import { Meteor } from 'meteor/meteor';

export default Links = new Mongo.Collection('links');

if(Meteor.isServer) {
  Meteor.publish('links', () => {
    return Links.find({});
  });
}

client/main.js 中,您将订阅该出版物,并等待它准备就绪,然后再继续您的补水。你可以用meteor/tracker 来做到这一点,因为ready() 是一个可观察的。

import React from 'react';
import ReactDOM from 'react-dom';
import { Meteor } from 'meteor/meteor';
import { onPageLoad } from "meteor/server-render";
import App from '../imports/ui/entry_points/ClientEntryPoint';
import { Tracker } from 'meteor/tracker';

onPageLoad(async sink => {
  Tracker.autorun(computation => {
    if(Meteor.subscribe('links').ready()) {
      ReactDOM.hydrate(
        <App />,
        document.getElementById("react-target")
      );
      computation.stop();
    }
  })
});

显然,这需要订阅整个应用程序中的所有内容,但您可以添加额外的逻辑来根据路由订阅不同的内容。

【讨论】:

    【解决方案2】:

    我已经为您创建了一个包,可以防止组件在页面加载时重新呈现。

    在这里查看https://github.com/pravdomil/Meteor-React-SSR-and-CSR-with-loadable-and-subscriptions

    【讨论】:

    • 感谢发帖!有点不清楚我将如何使用它。查看源代码,我看到您正在覆盖 Meteor.subscribe,这让我有点紧张(因为现实世界的案例非常大并且正在生产中)。你能说明你将如何使用它来处理这里的动物吗?
    • 我希望这个解决方案能够工作——但它不适合我。也许我没有正确实施它,但是指导太少了,无法确定。我在 repo 上提出了一个更完整的问题。谢谢
    【解决方案3】:

    您可以使用.ready() 使其在订阅尚未准备好时不呈现,例如:

    const animalSub = Meteor.subscribe('animals')
    
    if (animalSub.ready()) {
      return AnimalsData.find().fetch()
    }
    

    【讨论】:

    • 你能详细说明一下吗? Meteor.subscribe-statement 在 withTracker-function 内部,所以问题是当它“什么都不做”时,它仍然调用 AnimalList 的渲染,这是我试图避免的问题。
    • 它正在调用,因为您没有将返回函数包装在 ready() 中。您只需要将返回函数包装在 .ready 中,这将导致如果订阅尚未准备好,它将不会渲染组件。我在我的手机上使用 atm,所以很难格式化代码。我想我已经给了你足够的信息来展示它是如何工作的
    • 已编辑我的答案,请再看一遍:)
    • 很遗憾,这不是一个正确的解决方案。我假设您想将该代码放入 withTracker 中?每当animalSub 更改和启动时都会调用withTracker。您的代码正在做的是它在可用时返回正确的数据。不可用时(animalSub.ready()之前),withTracker仍然运行,但由于没有return语句,返回undefined,调用重渲染(数据不正确)
    猜你喜欢
    • 2023-04-09
    • 1970-01-01
    • 2018-01-05
    • 1970-01-01
    • 1970-01-01
    • 2019-08-07
    • 1970-01-01
    • 2015-05-28
    相关资源
    最近更新 更多