score:3

Accepted answer

I'm using wrapper around Route, which checks if users are logged in and if not, redirect them to login page. Wrapped routes are rendered only after userId of authenticated user is fetched.

import * as React from 'react'
import { Route, Redirect } from 'react-router-dom'
import URLSearchParams from 'url-search-params'

class AuthRoute extends React.Component {
  componentDidMount() {
    if (!this.props.isLoading) {
      this.props.getLoggedInUserId()
    }
  }

  render() {
    if (this.props.isLoading) {
      // first request is fired to fetch authenticated user
      return null // or spinner
    } else if (this.props.isAuthenticated) {
      // user is authenticated
      return <Route {...this.props} />
    } else {
      // invalid user or authentication expired
      // redirect to login page and remember original location
      const search = new URLSearchParams({
        next: this.props.location.pathname,
      })
      const next =
        this.props.location.pathname !== '/' ? `?${search.toString()}` : ''
      return <Redirect to={`/login${next}`} />
    }
  }
}

You need to update your reducer which handle getLoggedInUserId action to store also isLoading state.

score:0

OP writing. After reading nice ideas here, I decided to go with a custom HOC:

import React, { Component } from 'react';

const requireProp = (As, propsSelector, propsToDispatch) =>
  class Wrapper extends Component {
    componentWillMount() {
      if (!propsSelector(this.props) && typeof propsToDispatch === 'function') {
        propsToDispatch(this.props);
      }
    }

    render() {
      const { ...props } = this.props;
      return !!propsSelector(this.props) && <As {...props} />;
    }
  };

export default requireProp;

To see how I use it, see this gist.

score:2

I think using HOC will be clean here. As all the common logic will be at the same place. Use composition here Let say you have components A, B, C, D

Now you want to write some common function on the componentWillReceiveProps lifecycle of all the components.

Write a HOC like:

class HOC extends React.Component {
componentWillReceiveProps(nextProps) {
//Your commomn logic
}
render() {
const childrenWithProps = React.Children.map(this.props.children,
 child => React.cloneElement(child, {
   ...this.props,
 })
 return (
  <div>
   {childrenWithProps}
  </div>
 )
}
}

Write your components like this:

class A extends React.Component {
componentWillReceiveProps(nextProps) {
  //your uncommone logic
}
render(){
 return (
   <HOC {...this.props}>
    <div>
     //Your page jsx
    </div>
   </HOC>
 )
}
}

same way write for component B, C, and D. This pattern is useful when there is lot common among components. So better have a look at your usecase

score:3

You probably want the initial state to be rendered by the server into 'index.html' (or what have you) and hydrated on the client.

This initial state would include loggedInUserId and data for the /comments page.

Check out https://redux.js.org/docs/recipes/ServerRendering.html


Related Query

More Query from same tag