catandmouse
catandmouse

Reputation: 11819

What component lifecycle to use to do something before render()?

I need to check whether some props (from redux store) is an empty object or not. If it is empty, I want the page to redirect to another page and not bother to call render().

The current flow is something like:

constructor(props) {
   this.checkObject();
}

checkObject() {
  if (Object.keys(someObj).length === 0 && someObj.constructor === Object) {
    this.props.history.push("/some-other-route");
  }
}

render() {
   // some code
}

However, when I do a console.log, render() is being called after checkObject() which causes some errors because render() needs a non-empty object to display content properly. That's the reason I don't want react to even call render() if the object is empty (which I check through checkObject()) and just redirect to another page.

So is there a lifecycle method to use that will execute my redirection code before render() is called?

Upvotes: 3

Views: 2422

Answers (4)

Estus Flask
Estus Flask

Reputation: 222979

history.push() is a side effect that won't prevent the component to be initially rendered, so it belongs to componentDidMount.

Since the result depends on props, the check could go to getDerivedStateFromProps to provide redirect flag in a component with local state. In a component that is connected to Redux it can be performed in mapStateToProps:

connect(({ someObj }) => ({ redirect: !Object.keys(someObj) }))(...)

The component shouldn't be rendered if it will redirect:

componentDidMount() {
  if (this.props.redirect)
    this.props.history.push("/some-other-route");
}

render() {
   return !this.props.redirect && (
     ...
   );
}

As another answer correctly mentions, <Redirect> component is a declarative alternative to calling history.push() directly.

Upvotes: 0

saman.shahmohamadi
saman.shahmohamadi

Reputation: 485

Update: Add super(props) to your constructor. I think it should solve the problem. In this case, no need to componentWillMount(). Your code should work just fine.

Unsafe and temporary solution:
You can use componentWillMount().

The first true life cycle method called is componentWillMount(). This method is only called one time, which is before the initial render.

constructor(props) {

}

checkObject() {
  if (Object.keys(someObj).length === 0 && someObj.constructor === Object) {
    this.props.history.push("/some-other-route");
  }
}

componentWillMount() {
  this.checkObject();
}

render() {
   // some code
}

Upvotes: 0

anuragb26
anuragb26

Reputation: 1475

You could use the Redirect component of react-router within render.

import { Redirect } from 'react-router'
render(){

 (checkIfObjectEmpty)?<Redirect to = '/some_route'/>:<JSX>

}

Upvotes: 2

aseferov
aseferov

Reputation: 6403

Return inside render

constructor(props) {
    this.checkObject();
}

checkObject() {
    return Object.keys(someObj).length === 0 && someObj.constructor === Object
}

render() {
    if(this.checkObject()) return <Redirect to=/some-other-route" />

    //rest of code not run if object is empty
}

Upvotes: 0

Related Questions