lifecycle+hooks

 

by Elizaveta Anatskaya

Agenda

  • Lifecycle methods
  • Hooks

What is lifecycle?

A React component is a reusable piece of code receiving props to communicate with the outside world.

 

1. An instance of a component is created.

2. The component’s UI is computed (rendering) and mounted into the DOM.
3. Then an event occurs (e.g. user keystroke) and the already existing component will get new props. The component will be updated and thus will rerender.
4. The component is unmounted (e.g. routing)

2

Lifecycle

MOUNTING

UPDATING

UNMOUNTING

 

Component is ready to mount in the browser

 

 

Component is updated in two ways: sending the new props and updating the state

 

Component is not needed and anmouned from the DOM

 

constructor()

static getDerivedStateFromError()
render()
componentDidMount()

static getDerivedStateFromError()

render()
componentDidUpdate()

shouldComponentUpdate()

componentWillUnmount()

Lifecycle diagram

constructor()

 

If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor.

Most Common Use Case:

  • Initializing local state by assigning an object to this.state.
  • Binding event handler methods to an instance.
constructor(props) {
  super(props);
  // Don't call this.setState() here!
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}

 handleClick() {
    alert(this.state.message);
  }
// you may enable the experimental
//  Class Properties syntax proposal with Babel
state = { counter: 0 }

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

// Using an arrow here binds the method:
handleClick = () => {
  alert(this.state.message);
}

MOUNTING

render()

 

 is the only required method in a class component.

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

render() won't be invoked if shouldComponentUpdate() returns false

 render() {
   const {value} = this.props.value;
   return (
     <input type="button" value={value} onClick={this.logMessage} />
);
  • React elements. 

  • Arrays and fragments.

  • Portals. 

  • String and numbers. 

  • Booleans or null.

MOUNTING

componentDidMount()

 

 is invoked immediately after a component is mounted (inserted into the tree)

 

Most Common Use Case:

  • Starting AJAX calls to load in data for your component.
  • Adding event listeners
  • DOM or state updates

 

componentDidMount() {
  fetch(url).then(res => {
    // Handle response in the way you want.
    // Most often with editing state values.
  })
}

MOUNTING

static getDerivedStateFromProps ()

 

this method is meant to be pure and is fired on every render, regardless of the cause.

 

Most Common Use Case:

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

 

   
  class EmailInput extends Component {
      state = {
        email: this.props.defaultEmail,
        prevPropsUserID: this.props.userID
      };

      static getDerivedStateFromProps(props, state) {
        // everytime current user is changes, 
        // reset state which is linked to this user (email)
        if (props.userID !== state.prevPropsUserID) {
          return {
            prevPropsUserID: props.userID,
            email: props.defaultEmail
          };
        }
        return null;
      }
      // ...
  }

UPDATING

shouldComponentUpdate ()

 

answers the question, “should I re-render?”

 

allows us to say: only update if the props you care about change

 

 

Most Common Use Case:

Controlling exactly when your component will re-render.

 

shouldComponentUpdate(nextProps, nextState)

UPDATING

shouldComponentUpdate(nextProps, nextState) {
 return !shallowEqual(nextProps, this.props) || !shallowEqual(nextState, this.state);
}

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.

 
 

Most Common Use Case: Taking a look at some attribute of the current DOM, and passing that value on to componentDidUpdate.

 

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // Are we adding new items to the list?
    // Capture the scroll position so we can adjust scroll later.
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

UPDATING

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().

 
 

Most Common Use Case:

Cleaning up any leftovers  from your component.

componentWillUnmount() {
    this.removeClickListener();
    this.removeKeyboardListener();
  }

UNMOUNTING

Error boundaries

 

getDerivedStateFromError()

 
 
static getDerivedStateFromError(error)

UNMOUNTING

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

A class component becomes an error boundary if it defines either (or both) of the lifecycle methods

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

componentDidCatch()

 
 
componentDidCatch(error, info)

Most Common Use Case:

Catching and logging errors.

Legacy

 

Hooks

 

are functions that helps to use state, lifecycle methods and other React features without writing a class.

Motivation

It’s hard to reuse stateful logic between components

Hooks allow to reuse stateful logic without changing component hierarchy.

Complex components become hard to understand

Hooks let to split one component into smaller functions based on what pieces are related

Classes confuse both people and machines

Hooks let to use more of React’s features without classes.

✌️ Rules of Hooks

 
  • Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.
     
  • Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions.

📌 State Hook

 
  • useState returns a pair: the current state value and a function that lets you update it. You can call this function from an event handler or somewhere else. It’s similar to this.setState in a class, except it doesn’t merge the old and new state together.
  • The only argument to useState is the initial state.

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

⚡️ Effect Hook

 

side effects
are data fetching, subscriptions, or manually changing the DOM from React components before. We call these operations  (or “effects” for short) because they can affect other components and can’t be done during rendering.

Adds the ability to perform side effects from a function component. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes, but unified into a single API.

 
 
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

📌 UseRef

 

returns a mutable ref object whose .current property is initialized to the passed argument (initialValue).

 

mutating the .current property doesn’t cause a re-render.

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

Controlled Components

 
  • are ones where form data is stored in the component’s state and updated by an “onChangeHandler”.
  • an input form element whose value is controlled by React in this way is called a “controlled component”.
handleChange(event) {
    this.setState({value: event.target.value});
  }

<input 
	type="text" 
	value={this.state.value} 
	onChange={this.handleChange} 
/>

Unontrolled Components

 
function CustomTextInput(props) {
  // textInput must be declared here so the ref can refer to it
  const textInput = useRef(null);
  
  function handleClick() {
    textInput.current.focus();
  }

  return (
    <div>
      <input
        type="text"
        ref={textInput} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}

components where the DOM handles the form data

📌 UseContext?

 

returns a mutable ref object whose .current property is initialized to the passed argument (initialValue).

 

mutating the .current property doesn’t cause a re-render.

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

Thanks!

Lecture 2

By Elizabeth Anatskaya