3

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

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

页面加载后,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. 数据到达时在客户端呈现 [动物数据]
4

3 回答 3

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();
    }
  })
});

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

于 2019-09-07T15:29:06.680 回答
0

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

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

于 2018-02-13T18:52:01.650 回答
-1

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

const animalSub = Meteor.subscribe('animals')

if (animalSub.ready()) {
  return AnimalsData.find().fetch()
}
于 2018-02-09T13:31:34.687 回答