Component life cycle methods



Each component has several “lifecycle methods” that you can override to run code at particular times in the process. You can use this lifecycle diagram as a cheat sheet. In the list below, commonly used lifecycle methods are marked as bold. The rest of them exist for relatively rare use cases.

 

Mounting

 

These methods are called in the following order when an instance of a component is being created and inserted into the DOM:

 

•             constructor()

•             static getDerivedStateFromProps()

•             render()

•             componentDidMount()

 

Note:

These methods are considered legacy and you should avoid them in new code:

 

•             UNSAFE_componentWillMount()

 

Updating

 

An update can be caused by changes to props or state. These methods are called in the following order when a component is being re-rendered:

 

•             static getDerivedStateFromProps()

•             shouldComponentUpdate()

•             render()

•             getSnapshotBeforeUpdate()

•             componentDidUpdate()

 

Note:

These methods are considered legacy and you should avoid them in new code:

 

•             UNSAFE_componentWillUpdate()

•             UNSAFE_componentWillReceiveProps()

 

Unmounting

 

This method is called when a component is being removed from the DOM:

 

•             componentWillUnmount()

 

Error Handling

 

These methods are called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component.

 

•             static getDerivedStateFromError()

•             componentDidCatch()

 

constructor:

 

The first thing that gets called is your component constructor, if your component is a class component. This does not apply to functional components.

 

Your constructor might look like so:

 

class MyComponent extends Component {

  constructor(props) {

    super(props);

    this.state = {

      counter: 0,

    };

  }

}

 

The constructor gets called with the component props. You must call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor, which can lead to bugs.

 

You can then initialize your state, setting the default values. You can even base the state on the props:

 

class MyComponent extends Component {

  constructor(props) {

    super(props);

    this.state = {

      counter: props.initialCounterValue,

    };

 }

}

 

Note that using a constructor is optional, and you can initialize your state like so if your Babel setup has support for class fields:

 

class MyComponent extends Component {

  state = {

    counter: 0,

  };

}

 

This approach is widely preferred. You can still base your state off props:

 

class MyComponent extends Component {

  state = {

    counter: this.props.initialCounterValue,

  };

}

 

You may still need a constructor, though, if you need to use a ref. Here’s an example:

 

class Grid extends Component {

  constructor(props) {

    super(props);

    this.state = {

      blocks: [],

    };

               

    this.grid = React.createRef();

  }

 

We need the constructor to call createRef, to create a reference to the grid element.

 

You can also use the constructor for function binding, which is also optional.

 

You should not call setState() in the constructor(). Instead, if your component needs to use local state, assign the initial state to this.state directly in the constructor:

 

constructor(props) {

  super(props);

  // Don't call this.setState() here!

  this.state = { counter: 0 };

  this.handleClick = this.handleClick.bind(this);

}

 

Constructor is the only place where you should assign this.state directly. In all other methods, you need to use this.setState() instead.

 

Note

 

Avoid copying props into state! This is a common mistake:

 

constructor(props) {

super(props);

// Don't do this!

this.state = { color: props.color };

}

 

The problem is that it’s both unnecessary (you can use this.props.color directly instead), and creates bugs (updates to the color prop won’t be reflected in the state).

 

Most Common Use Case For Constructor: Setting up state, creating refs and method binding.

 

getDerivedStateFromProps():

 

getDerivedStateFromProps is invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, or null to update nothing.

 

static getDerivedStateFromProps(props, state) {

  return { blocks: createBlocks(props.numberOfBlocks) };

}

 

Note that we could have placed this code in the constructor. The advantage of getDerivedStateFromProps is that it is more intuitive—it’s only meant for setting state, whereas a constructor has multiple uses.

 

Note that this method is fired on every render, regardless of the cause. This is in contrast to UNSAFE_componentWillReceiveProps, which only fires when the parent causes a re-render and not as a result of a local setState.

 

Most Common Use Case For getDerivedStateFromProps (during mount):Returning a state object based on the initial props.

 

render:

 

The render() method is the only required method in a class component.

 

When called, it should examine this.props and this.state and return one of the following types:

 

React elements. Typically created via JSX. For example, <div /> and <MyComponent /> are React elements that instruct React to render a DOM node, or another user-defined component, respectively.

 

Arrays and fragments. Let you return multiple elements from render. See the documentation on fragments for more details.

Portals. Let you render children into a different DOM subtree.

 

String and numbers. These are rendered as text nodes in the DOM.

 

Booleans or null. Render nothing. (Mostly exists to support return test && <Child /> pattern, where test is boolean.)

 

The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it’s invoked, and it does not directly interact with the browser.

 

If you need to interact with the browser, perform your work in componentDidMount() or the other lifecycle methods instead. Keeping render() pure makes components easier to think about.

 

Note

 

render() will not be invoked if shouldComponentUpdate() returns false.

 

componentDidMount:

 

componentDidMount() is invoked immediately after a component is mounted (inserted into the tree). Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.

 

This method is a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe in componentWillUnmount().

 

Updating

 

getDerivedStateFromProps:

 

Yep, this one again. Now, it’s a bit more useful.

 

If you need to update your state based on a prop changing, you can do it here by returning a new state object.

 

Again, hanging state based on props is not recommended. It should be considered a last resort.

 

shouldComponentUpdate:

 

Use shouldComponentUpdate() to let React know if a component’s output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.

 

shouldComponentUpdate() is invoked before rendering when new props or state are being received. Defaults to true. This method is not called for the initial render or when forceUpdate() is used.

 

This method only exists as a performance optimization. Do not rely on it to “prevent” a rendering, as this can lead to bugs. Consider using the built-in PureComponent instead of writing shouldComponentUpdate() by hand. PureComponent performs a shallow comparison of props and state, and reduces the chance that you’ll skip a necessary update.

 

If you are confident you want to write it by hand, you may compare this.props with nextProps and this.state with nextState and return false to tell React the update can be skipped. Note that returning false does not prevent child components from re-rendering when their state changes.

 

We do not recommend doing deep equality checks or using JSON.stringify() in shouldComponentUpdate(). It is very inefficient and will harm performance.

 

render:

 

Same as before!

 

getSnapshotBeforeUpdate:

 

getSnapshotBeforeUpdate(prevProps, prevState)

 

getSnapshotBeforeUpdate() is invoked right before the most recently rendered output is committed to e.g. the DOM. It enables your component to capture some information from the DOM (e.g. scroll position) before it is potentially changed. Any value returned by this lifecycle will be passed as a parameter to componentDidUpdate().

 

This use case is not common, but it may occur in UIs like a chat thread that need to handle scroll position in a special way.

 

A snapshot value (or null) should be returned.

 

componentDidUpdate:

 

componentDidUpdate(prevProps, prevState, snapshot)

 

Now, our changes have been committed to the DOM. componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render.

 

Use this as an opportunity to operate on the DOM when the component has been updated. This is also a good place to do network requests as long as you compare the current props to previous props (e.g. a network request may not be necessary if the props have not changed).

 

componentDidUpdate(prevProps) {

  // Typical usage (don't forget to compare props):

  if (this.props.userID !== prevProps.userID) {

    this.fetchData(this.props.userID);

  }

}

You may call setState() immediately in componentDidUpdate() but note that it must be wrapped in a condition like in the example above, or you’ll cause an infinite loop. It would also cause an extra re-rendering which, while not visible to the user, can affect the component performance.

 

If your component implements the getSnapshotBeforeUpdate() lifecycle (which is rare), the value it returns will be passed as a third “snapshot” parameter to componentDidUpdate(). Otherwise this parameter will be undefined.

 

Note

 

componentDidUpdate() will not be invoked if shouldComponentUpdate() returns false.

 

Unmounting

 

componentWillUnmount:

 

componentWillUnmount() is invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, or cleaning up any subscriptions that were created in componentDidMount().

 

You should not call setState() in componentWillUnmount() because the component will never be re-rendered. Once a component instance is unmounted, it will never be mounted again.

 

Errors

 

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

 

A class component becomes an error boundary if it defines either (or both) of the lifecycle methods static getDerivedStateFromError() or componentDidCatch(). Updating state from these lifecycles lets you capture an unhandled JavaScript error in the below tree and display a fallback UI.

 

Only use error boundaries for recovering from unexpected exceptions; don’t try to use them for control flow.

 

getDerivedStateFromError:

 

static getDerivedStateFromError(error)

This lifecycle is invoked after an error has been thrown by a descendant component. It receives the error that was thrown as a parameter and should return a value to update state.

 

class ErrorBoundary extends React.Component {

  constructor(props) {

    super(props);

    this.state = { hasError: false };

  }

 

  static getDerivedStateFromError(error) {

    // Update state so the next render will show the fallback UI.

    return { hasError: true };

  }

 

  render() {

    if (this.state.hasError) {

      // You can render any custom fallback UI

      return <h1>Something went wrong.</h1>;

    }

 

    return this.props.children;

  }

}

 

Note

 

getDerivedStateFromError() is called during the “render” phase, so side-effects are not permitted. For those use cases, use componentDidCatch() instead.

 

Most Common Use Case for getDerivedStateFromError: Updating state to display an error screen.

 

componentDidCatch:

 

componentDidCatch(error, info)

This lifecycle is invoked after an error has been thrown by a descendant component. It receives two parameters:

 

error - The error that was thrown.

info - An object with a componentStack key containing information about which component threw the error.

componentDidCatch() is called during the “commit” phase, so side-effects are permitted. It should be used for things like logging errors:

 

class ErrorBoundary extends React.Component {

  constructor(props) {

    super(props);

    this.state = { hasError: false };

  }

 

  static getDerivedStateFromError(error) {

    // Update state so the next render will show the fallback UI.

    return { hasError: true };

  }

 

  componentDidCatch(error, info) {

    // Example "componentStack":

    //   in ComponentThatThrows (created by App)

    //   in ErrorBoundary (created by App)

    //   in div (created by App)

    //   in App

    logComponentStackToMyService(info.componentStack);

  }

 

  render() {

    if (this.state.hasError) {

      // You can render any custom fallback UI

      return <h1>Something went wrong.</h1>;

    }

 

    return this.props.children;

  }

}

 

Note

 

In the event of an error, you can render a fallback UI with componentDidCatch() by calling setState, but this will be deprecated in a future release. Use static getDerivedStateFromError() to handle fallback rendering instead.

 

Most Common Use Case for componentDidCatch: Catching and logging errors.

Comments

Popular posts from this blog

Set Up Babel and Webpack

Typescript Setup

Typescript + React Setup