简体   繁体   中英

React Pre-Render Conditionals

Before I load my React App I need to check 2 conditions

  1. User is Logged in, if not redirect to login page
  2. All of the User Settings fetched using API, if not display a loading screen.

So, inside render method, I have below conditions:

if (!this.isUserLoggedIn()) return <NotifyPleaseLogin />;
else if (!this.state.PageCheck) {
  return (
    <PageLoading
      clientId={Config.clientId}
      setPageReady={this.setPageReady()}
    />
  );
} else {
  return "Display the page";

In this scenario, what I expect to see happen is that, if user is not logged in, user redirected to login page. If user logged in and currently page is fetching the API query, user will see the PageLoading component (loading screen) and lastly if page is ready, the page will get displayed.

Right now I am getting Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state. Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state. error, which is because I am doing a setState update within Render method of the parent and also I am getting TypeError: props.setPageReady is not a function at PageLoading.js:29 error when I try to run parent's function that sets the state of PageReady to true like below

setPageReady() {
    this.setState({ PageCheck: true });
  }

How can I set this up so child can display a loading page until the page is ready (During this child can do an API call and retrieve user settings) then let parent know all settings are retrieved and are in the redux so parent can proceed loading the page?

You can easily achieve this by adding more states to actively control your component:

state = {
    isAuthorized: false,
    pagecheck: false    
};

We move the authorization check to a lifecylcle-method so it doesn't get called every render.

componentDidMount() {
    if(this.isUserLoggedIn()) {
        this.setState({ 
            isAuthorized: true                
        });
    }   
}

Using our state, we decide what to render.

render() {
    const {
      pagecheck,
      isAuthorized
    } = this.state;

    if(!isAuthorized){
      return <NotifyPleaseLogin />;
    }

    if(!pagecheck) {
      return (
        <PageLoading
          clientId={Config.clientId}
          setPageReady={() => this.setPageReady()}
        />
      );    
    }

    return "Display the page";
}

Note: Previously you passed this.setPageReady() to Pageloading. This however executes the function and passes the result to Pageloading. If you want to pass the function you either need to remove the braces this.setPageReady or wrap it into another function () => this.setPageReady()

You can pass PageCheck as prop from Parent to and show/hide loader in component based on that prop.

  <PageLoading
      clientId={Config.clientId}
      pageCheck={this.state.PageCheck}
     setPageReady={this.setPageReady}
    />

Then call setPageReady inside the success and error of the API call that you make in the child function:

axios.get(api)
.then((response) => {
     //assign or do required stuff for success
   this.props.setPageReady();
})
.catch((error) => {
    //do error related stuff
this.props.setPageReady();  //as you need to hide loader for error condition as well
})
state = {
    isAuthorized: false,
    pageCheck: false    
};

componentDidMount() {
    if(this.isUserLoggedIn()) {
        this.setState({ 
            isAuthorized: true                
        });
    }   
}

{!this.state.isAuthorized ?
  <NotifyPleaseLogin />
:
(!this.state.pageCheck ?
  <PageLoading
      clientId={Config.clientId}
      setPageReady={this.setPageReady()}
   />
  :
  "Display the page")  
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM