Baspa
Baspa

Reputation: 1168

Does returning null in a component prevents child components from rendering?

I have a LoadingProvider where I set the state of my Loading component to false and when needed to true. I want to show my Loading component only when the state of loading equals to true.

All my providers, router and app components are loaded in my root.js:

import React, { Component } from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { MuiPickersUtilsProvider } from "material-ui-pickers";
import MomentUtils from "@date-io/moment";

import App from "./App";
import { DeleteDialogProvider } from "/hocs/withDeleteDialog";
import { WarningDialogProvider } from "/hocs/withWarningDialog";
import { LoadingProvider } from "/hocs/withLoading";

import { MuiThemeProvider, createMuiTheme } from "@material-ui/core/styles";
import { StateProvider } from "/hocs/withState";
import { I18nProvider } from "/hocs/withI18n";

const theme = createMuiTheme({});

class Root extends Component {
  render() {
    return (
      <MuiThemeProvider theme={theme}>
        <MuiPickersUtilsProvider utils={MomentUtils}>
          <I18nProvider>
            <DeleteDialogProvider>
              <WarningDialogProvider>
                <StateProvider>
                  <Router>
                    <LoadingProvider>
                      <App />
                    </LoadingProvider>
                  </Router>
                </StateProvider>
              </WarningDialogProvider>
            </DeleteDialogProvider>
          </I18nProvider>
        </MuiPickersUtilsProvider>
      </MuiThemeProvider>
    );
  }
}

export default Root;

My other providers don't block any other components from rendering. But when I add the LoadingProvider in root.js and check the console with the React Developer Tools I see it doesn't load/render the components that comes after my LoadingProvider component. The problem is that I don't know why it doesn't render any other components.

This is my withLoading file where I define the LoadingProvider:

import React, { Component } from "react";
import Loading from "/components/Loading";

const LoadingContext = React.createContext();

export class LoadingProvider extends Component {
    constructor(props) {
        super(props);

        this.state = {
            loading: false
        };
    }

    setLoadingContext = e => {
        this.setState({
            loading: true
        });
    };

    render() {

        return (
            <LoadingContext.Provider value={this.setLoadingContext}>
                <Loading
                    loading={this.state.loading}
                />
            </LoadingContext.Provider>
        );
    }
}

export const withLoading = Component => props => (
    <LoadingContext.Consumer>
        {setLoadingContext => (
            <Component {...props} setLoadingContext={setLoadingContext} />
        )}
    </LoadingContext.Consumer>
)

And this is my Loading.js file where I define my Loading component:

import React, { Component } from 'react';
import CircularProgress from '@material-ui/core/CircularProgress';

class Loading extends Component {
    render() {

        const loading = this.props;

        // TODO: fix weird repetitive loading prop
        if (!loading.loading) {
            return null;
        } else {
            return (
                <CircularProgress />
            );
        }
    }
}

export default Loading;

I guess it has something to do with returning null when loading is false. But when I comment that rule of code out it says:

Uncaught Invariant Violation: Loading(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.

Upvotes: 2

Views: 430

Answers (2)

Joseph D.
Joseph D.

Reputation: 12174

This is primarily because in your LoadingProvider you are not using props.children.

<LoadingContext.Provider value={this.setLoadingContext}>
  <Loading
    loading={this.state.loading}
  />
  {this.props.children} // add this
</LoadingContext.Provider>

Take note that null don't render anything.

Upvotes: 1

RemcoGerlich
RemcoGerlich

Reputation: 31260

Your <App/> is passed to LoadingProvider in its children property. But LoadingProvider doesn't do anything with its children, so nothing happens.

So return this.props.children when you want them to render.

Upvotes: 1

Related Questions