React Lazy loading

Good day.


I am developing a project on React and Redux. I want to describe the architecture of my project in this article.

So, let's begin. File structure:



To connect reducers, create a singleton reducerRegister class:

./reducerRegister.js
class ReducerRegistry {
  constructor () {
    if (!ReducerRegistry.instance) {
      this._emitChange = null
      this._reducers = {}
      ReducerRegistry.instance = this
    }
    return ReducerRegistry.instance
  }
  getReducers () {
    return {...this._reducers}
  }
  register (name, reducer) {
    this._reducers = {...this._reducers, [name]: reducer}
    if (this._emitChange) {
      this._emitChange(this.getReducers())
    }
  }
  setChangeListener (listner) {
    this._emitChange = listner
  }
}
const reducerRegistry = new ReducerRegistry()
export default reducerRegistry

With this class, reducers can register themselves in the store.

Create a store:


./configureStore
export default function configureStore (initialState) {
  const combine = (reducers) => {
    const reducerNames = Object.keys(reducers)
    Object.keys(initialState).forEach(item => {
      if (reducerNames.indexOf(item) === -1) {
        reducers[item] = (state = null) => state
      }
    })
    reducers['router'] = connectRouter(history)
    return combineReducers(reducers)
  }
  const reducer = combine(reducerRegistry.getReducers())
  const store = createStore(reducer, initialState, compose(composeWithDevTools(applyMiddleware(thunk)), applyMiddleware(routerMiddleware(history))))
  reducerRegistry.setChangeListener(reducers => {
    store.replaceReducer(combine(reducers))
  })
  return store
}

Using the store.replaceReducer function, load reducers into the store.

Main file


Add routes and connect redux

./index.js
const Cabinet = React.lazy(() => import('./moduleCabinet/Index'))
let store = configureStore({
  profile: {loading: null}
})
class App extends Component {
  render () {
    const history = createBrowserHistory()
    return (
      }>
            }/>
              }}/>
              
page not found
} />
) } } if (document.getElementById('app')) { ReactDOM.render( , document.getElementById('app') ) }

Using React.lazy we make lazy loading of components. React.lazy is available starting from version 16.6: React. Lazy loading. The Suspense element is handling component loading.

AdminModule can only be downloaded by an authorized user, for this we use the RouteAdmin component:

./RouteAdmin.js
const NotAccess = (props) => {
  return (
    

Доступ закрыт

) } export default class RouteAdmin extends Component { constructor (props) { super(props) this.state = { component: null } } componentDidMount () { axios.post('/admin').then(data => data.data).then(data => { if (data.auth === true) { const Admin = React.lazy(() => import('./moduleAdmin/Index')) this.setState({component: Admin}) } else { this.setState({component: NotAccess}) } }) } render () { const Component = this.state.component return ( ) } }

Module implementation


Main file - add module routes

./moduleAdmin/Index.js
export default class IndexComponent extends Component {
  constructor (props) {
    super(props)
  }
  render () {
    return (
      <>
        
        ...
      
    )
  }
}

./moduleAdmin/pages/Profiles.js
class Profiles extends Component {
    componentDidMount() {
        this.props.getInfo()
    }
    render() {
        if (this.props.loading === Process.Start) {
            return 
        }
        if (this.props.loading === Process.Success) {
            return (
                

Profiles

) } return null } } const mapStateToProps = (state) => { return { loading: state.profiles.loading } } const mapDispatchToProps = (dispatch) => { return { getInfo: () => dispatch(getInfo()) } } export default connect( mapStateToProps, mapDispatchToProps )(Profiles)

Create a reducer


We immediately register it in the store:

./moduleAdmin/redux/profile.js
const Process = {
    Start: 0, Success: 1, Error: 2
}
export const getInfo = () => {
    return (dispatch) => {
        dispatch({ type: PROFILES_GET_START })
        axios.post('/news').then((data) => {
            dispatch({ type: PROFILES_GET_SUCCESS, payload: data.data })
        }).catch(e => {
            dispatch({ type: PROFILES_GET_ERROR, payload: e })
        })
    }
}
const initialState = {
    error: null, loading: null, data: null
}
const reducer = (state = initialState, action) => {
    switch (action.type) {
        case PROFILES_GET_START: {
            return { ...state, loading: Process.Start }
        }
        case PROFILES_GET_SUCCESS: {
            return { ...state, loading: Process.Success, data: action.payload}
        }
        case PROFILES_GET_ERROR: {
            return { ...state, loading: Process.Error, error: action.payload }
        }
        default: {
            return state
        }
    }
}
reducerRegistry.register('profiles', reducer)

I hope my article will help in the implementation of your project, and your comments will help improve mine.

Also popular now: