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)
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
Lecture 2
- 243