ReactJS预加载导航元素

时间:2018-12-18 12:03:05

标签: reactjs

我最近将静态导航栏从一般的html元素移到了页面的React渲染中,因为我想将动态加载通知的功能合并到可以在导航中触发的模式中。进行此更改后,我注意到导航页面不会在页面加载时立即显示,而是在componentDidMount() { this.fetchList(); }完成加载后立即显示。

我个人认为这是因为导航组件是在与该API提取有关的render()调用中设置的,并且由于在调用之后设置了此类,所以导航将不得不等到提取成功或失败返回。

如果这是真的,那是否意味着我需要将导航设置为更高的级别,以确保在页面加载带有样式和非反应性元素的页面时加载?

这是我的ReactDOM.render()

import React from 'react';
import ReactDOM from 'react-dom';
import AnnotationFeedContainer from './components/app/activity-feed/activity-feed.js';


ReactDOM.render(<AnnotationFeedContainer />, document.getElementById('annotation-card'));

这里是<AnnotationFeedContainer />,它正在渲染我的react元素(<Navigation />是我希望加载的组件,无论fetchList()为何,它都应加载):

import React from 'react';
import fetch from 'node-fetch';
import path from 'path';
import Navigation from '../navigation';
import AnnotationSearchForm from './annotation-search-form';
import OnboardingInformation from './onboarding/information';
import ActivityFeedNotifications from './notifications/notifications';
import AnnotationFeed from './annotation-card/annotation-card-feed';
import { API_ROOT } from '../config/api-config';

//GET /api/test and set to state
export default class AnnotationFeedContainer extends React.Component{
    constructor(props, context) {
        super(props, context);
        this.state = this.context.data || window.__INITIAL_STATE__ || { annotations: [], isLoading: true, onboardingWelcome: false, notifications: [] };
    }

    fetchList() {
            fetch(`${API_ROOT}` + '/api' + window.location.search, { compress: false })
                .then(res => {
                    return res.json();
                })  
                .then(data => {
                    console.log(data);
                    this.setState({ annotations: data.annotation, user: data.user, csrf: data.csrfToken, isLoading: false, onboardingWelcome: data.onboardingWelcome, notifications: data.notifications, feedPreference: data.feedPreference });
                }) 
                .catch(err => {
                    console.log(err);
                });
    }

    componentDidMount() {
        this.fetchList();
    }

    render() {
        if(this.state.feedPreference === 1){    
            return (
                <div>
                    <Navigation notifications={this.state.notifications}/>
                    <AnnotationSearchForm />
                    <div className="activity-feed-container">
                        <div className="container">
                            <OnboardingInformation onboarding={this.state.onboardingWelcome}/>
                            <LoadingIndicator loading={this.state.isLoading} />
                            <div className="row">
                                <div className="col-md-12">
                                    <AnnotationFeed {...this.state} />
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            )
        } else {
            return (
                <div className="activity-feed-container">
                    <div className="container">
                        <OnboardingInformation onboarding={this.state.onboardingWelcome}/>
                        <LoadingIndicator loading={this.state.isLoading} />
                        <div className="row">
                            <div className="col-md-6 col-md-offset-3">
                                <AnnotationFeed {...this.state} />
                            </div>
                            <div className="col-md-1 col-md-offset-1">
                                <ActivityFeedNotifications notifications={this.state.notifications} />
                            </div>
                        </div>
                    </div>
                </div>
            )
        }
    }
};

//Loading Indicator
const LoadingIndicator = props => {
    if(props.loading == true){
        return (
            <div className="spinner">
                <div className="bounce1"></div>
                <div className="bounce2"></div>
                <div className="bounce3"></div>
              <p>Loading...</p>
            </div>
        )
    } else {
        return null;
    }
}

导航组件:

import React from 'react';
import NotificationPopover from './activity-feed/notifications/notifications-popover';

//Navigation
export default class Navigation extends React.Component {
    render() {
        return (
            <nav className="navbar">
                <div className="container-fluid">
                    <div className="navbar-header">
                    <button type="button" className="navbar-toggle" data-toggle="collapse" data-target="#navigationLinks">
                        <span className="icon-bar mobile-nav-toggle"></span>
                        <span className="icon-bar mobile-nav-toggle"></span>
                        <span className="icon-bar mobile-nav-toggle"></span>
                    </button>
                        <a className="navbar-brand" href="/app"><img src="/images/synotate_logo.svg" className="nav-logo-svg"></img></a>
                    </div>
                    <div className="collapse navbar-collapse" id="navigationLinks">
                        <ul className="nav navbar-nav">
                            <li className="nav-item">
                                <a className="nav-link" href="/app">Activity Feed</a>
                            </li>
                            <li className="nav-item">
                                <a className="nav-link" href="/app/settings">Settings</a>
                            </li>
                        </ul>
                        <ul className="nav navbar-nav navbar-right">
                            <li className="nav-item">
                                <NotificationPopover notifications={this.props.notifications}/>
                            </li>
                            <li className="nav-item">
                                <a className="nav-link" href="/app/logout">Log Out</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        )
    }
}

2 个答案:

答案 0 :(得分:0)

在您的<AnnotationFeedContainer>中,您在if(this.state.feedPreference === 1)方法中有这行render()

除非您有一个成功的fetch()事件来自fetchList()中的componentDidMount(),否则该条件将为true;如果此条件返回true,则将呈现在其括号内,其中包括<Navigation>组件

否则,您将呈现另一个代码,我猜这是加载指示符,并且在这里,您没有包括Navigation组件,因此它不会显示。

这是您正在使用的逻辑,您告诉您的应用程序不包含Navigation组件,除非它获取您的数据,这在逻辑上是可以的! 如果您想以其他方式显示它,则可能要将其从您拥有的if语句中移出

答案 1 :(得分:0)

似乎您的访存调用负责将feedPreference变量设置为您的状态。

由于在您的if条件中使用了此变量,并且在未设置<Navigation/>时不会呈现feedPreference组件。

一个简单的解决方案是将<Navigation/>添加到else条件中(在<AnnotationFeedContainer/>的render函数中):

    } else {
        return (
            <>
                <Navigation notifications={this.state.notifications}/>
                <div className="activity-feed-container">
                    <div className="container">
                        <OnboardingInformation onboarding={this.state.onboardingWelcome}/>
                        <LoadingIndicator loading={this.state.isLoading} />
                        <div className="row">
                            <div className="col-md-6 col-md-offset-3">
                                <AnnotationFeed {...this.state} />
                            </div>
                            <div className="col-md-1 col-md-offset-1">
                                <ActivityFeedNotifications notifications={this.state.notifications} />
                            </div>
                        </div>
                    </div>
                </div>
            </>
        )
    }

一种更像“反应式”的操作方式可能是使用以下内容替换整个条件:

    return (
        <>
            <Navigation notifications={this.state.notifications} />
            {this.state.feedPreference === 1 && <AnnotationSearchForm />}
            <div className="activity-feed-container">
                <div className="container">
                    <OnboardingInformation onboarding={this.state.onboardingWelcome} />
                    <LoadingIndicator loading={this.state.isLoading} />
                    <div className="row">
                        {this.state.feedPreference === 1 ?
                            <>
                                <div className="col-md-6 col-md-offset-3">
                                    <AnnotationFeed {...this.state} />
                                </div>
                                <div className="col-md-1 col-md-offset-1">
                                    <ActivityFeedNotifications notifications={this.state.notifications} />
                                </div>
                            </>
                            :
                            <div className="col-md-12">
                                <AnnotationFeed {...this.state} />
                            </div>
                        }
                        <div className="col-md-6 col-md-offset-3">
                            <AnnotationFeed {...this.state} />
                        </div>
                        <div className="col-md-1 col-md-offset-1">
                            <ActivityFeedNotifications notifications={this.state.notifications} />
                        </div>
                    </div>
                </div>
            </div>
        </>
    )

使用内联ifs(&&)可以避免重复。如果您不能使用片段(<>是在最新的React版本中添加的),则可以将其替换为<div>标签