fridays / next-routes

Universal dynamic routes for Next.js
MIT License
2.47k stars 230 forks source link

Slow routing #316

Closed nihiluis closed 5 years ago

nihiluis commented 5 years ago

Hi, I'm having long loading times on pages which are wrapped with withRouter.

When I click a , I have to wait for 1s for my stuff to appear while on the top left corner I have a "loading..." message, otherwise completely blank.

It's from something like this

function DefaultLoading() {
  return react_1.default.createElement("p", null, "loading...");
}

How come? Is this related to next-routes or next itself? Or am I having ill code?

I'm using dynamic with no ssr and do several api calls (on mount, which should not prolong the initial dom loading).

routes.js

const Routes = require("next-routes")

const routes = new Routes()
  .add("invite", "/invite/:inviteId")
  .add("team", "/team/:teamId")
  .add("review/master", "/review/master/:reviewMasterId")
  .add("leader", "/leader/:leaderId")
  .add("user", "/user/:userId")
  .add("login")
  .add("leaders")

module.exports = routes

user.tsx

import * as React from "react"
import UI from "../src/components/ui"
import dynamic from "next/dynamic"

import * as style from "../src/style/single.scss"
import { withRouter } from "next/router";
import { DataLoader } from "../src/components/utils";
import RecentlyViewed from "../src/components/ui/sidebar/RecentlyViewed";
import Actions from "../src/components/ui/sidebar/Actions";
import UserSidebar from "../src/components/user/UserSidebar";
import UserView from "../src/components/user/UserView";

const DynamicAuth = dynamic(() => import("../src/components/auth/Auth"), {
  ssr: false
})

const User = props => {
  const { userId } = props.router.query

  return (
    <DynamicAuth>
      <DataLoader>
        <UI
          showSidebarLeft={false}
          sidebarLeftComponent={null}
          showSidebarRight={true}
          sidebarRightComponent={<UserSidebar />}>
          <div className={style.pageContent}>
            <UserView id={userId} />
          </div>
        </UI>
      </DataLoader>
    </DynamicAuth >)
}

export default withRouter(User)

UserView.tsx

import * as React from "react"
import { bindActionCreators, Dispatch } from "redux"
import { connect } from "react-redux"

import { RootState } from "../../redux"
import {
  User,
  UserActiveActions,
} from "../../redux/user"
import { TabMenu, TabContainer, Tab } from "polyvolve-frontend-common/lib";

import { PageTitle } from "../ui";
import { RecentlyViewedActions } from "../../redux/recentlyviewed";
import UserViewInformation from "./UserInformation";

import * as style from "../../style/overview/team.scss"
import * as singleStyle from "../../style/single.scss"
import UserViewDependencies from "./UserDependencies";
import { TeamOverviewActions, Team } from "../../redux/team";
import { getUserName } from "../../lib/format";
import { Leader, LeaderOverviewActions } from "../../redux/leader";

interface Props {
  loading: boolean
  initialized: boolean
  data?: User
  leaders: Leader[]
  id?: string
  error?: string
  activeActions?: typeof UserActiveActions
  leaderOverviewActions?: typeof LeaderOverviewActions
  recentlyViewedActions?: typeof RecentlyViewedActions
}

interface State {
  activeLeaderIds: string[]
  editting: boolean
  activeTab: number
}

class UserView extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props)

    this.state = {
      activeLeaderIds: [],
      editting: false,
      activeTab: 0
    }
  }

  componentDidMount() {
    const { id, recentlyViewedActions } = this.props

    this.grabCurrentUser(id)
    this.grabAllLeaders()

    // this is not type checked :/
    this.props.recentlyViewedActions!.addRecentlyViewedLocally({ type: "LEADER", targetId: id })
  }

  componentWillReceiveProps(newProps: Props) {
    const currentUserId = this.props.id
    const nextUserId = newProps.id

    if (nextUserId && currentUserId !== nextUserId) {
      this.grabCurrentUser(nextUserId)
    }

    if (this.props.data !== newProps.data) {
      const newLeaders = newProps.data ? newProps.data.leaders || [] : []
      this.setState({ activeLeaderIds: newLeaders.map(leader => leader.id) })
    }
  }

  grabCurrentUser = (id: string) => this.props.activeActions!.getUserRequest({ id })
  grabAllLeaders = () => this.props.leaderOverviewActions!.loadLeadersRequest()

  save = () => {
    this.setState({ editting: false })
  }

  updateTabIndex = (index: number) => this.setState({ activeTab: index })

  render(): JSX.Element {
    const {
      data,
      initialized,
      leaders,
      loading,
      activeActions } = this.props
    const { activeTab } = this.state

    // this data check is lazy. improve it later.
    return (
      <React.Fragment>
        {initialized && data && <div className={style.teamView}>
          <div className={singleStyle.header}>
            <PageTitle title={getUserName(data)} type={"User"} />
          </div>
          <TabMenu
            items={["Basic", "History", "Comments"]}
            activeIndex={activeTab}
            onClick={this.updateTabIndex}
            className={singleStyle.tabMenu}
            itemClassName={singleStyle.tabMenuItem} />
          <TabContainer className={singleStyle.tabContainer}>
            <Tab showWhenTab={0} currentTab={activeTab}>
              <UserViewInformation data={data} updateUser={activeActions.updateUserRequest} loading={loading} />
              <UserViewDependencies data={data} leaders={leaders} updateUser={activeActions.updateUserRequest} />
            </Tab>
          </TabContainer>
        </div>}
      </React.Fragment>
    )
  }
}

function mapStateToProps(state: RootState): Props {
  return {
    loading: state.user.active.loading,
    initialized: state.user.active.initialized,
    error: state.user.active.error,
    data: state.user.active.data,
    leaders: state.leader.overview.all,
  }
}

function mapDispatchToProps(dispatch: Dispatch<any>): Partial<Props> {
  return {
    activeActions: bindActionCreators(UserActiveActions, dispatch),
    leaderOverviewActions: bindActionCreators(LeaderOverviewActions, dispatch),
    recentlyViewedActions: bindActionCreators(RecentlyViewedActions, dispatch),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(UserView)
nihiluis commented 5 years ago

ok, the loading... from next still errs me, but the loading issue came from using href on instead of route.

The loading... is from the dynamic import. I just added this

const DynamicAuth = dynamic(() => import("../src/components/auth/Auth"), {
  ssr: false,
  loading: () => <p></p>
})