3

私のデータベースには、素敵な小さなリストにレンダリングしたい動物の配列があります。ユーザー エクスペリエンスを向上させるために、(新しいserver-renderパッケージを使用して) サーバー上でレンダリングし、 react-meteor-data( withTracker) を使用して変更をサブスクライブしたいと考えています。

現在、これは1つのことを除いて機能しています。サーバーはコンテンツ (データを含む) を期待どおりにレンダリングし、クライアントに送信します。問題はクライアントにあります。

ページが読み込まれると、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 に答える