Component
class-based vs functional
\ | class-based | functional
--- | --- | ---
props | yes, this.props | yes, it's from the input
state | yes, this.state | yes, useState()
lifecyle | yes | no
Class-based component is more powerful, it could be used as a Stateful component.
Functional componenet is simpler, it can be used as a Stateless component.
lifecycle
Mounting
-
constructor(props)
- Call
super(props), FIRST - Set up State, DO NOT call other functions, such as http request.
class MyComponent extends Component { constructor(props) { super(props); this.state = {name: 'my-component'}; } }or, an easier way to set state:
class MyComponent extends Component { state = {name: 'my-component'}; } - Call
-
getDerivedStateFromProps(props, state)
rarely used, sync the state from props
class MyComponent extends Component { static getDerivedStateFromProps(props, state) { return state; } } -
render()
- return JSX of current component
- render its child components
-
componentDidMount()
- call other functions, such as http request
- DO NOT cause re-rendering, like update states.
updating
-
getDerivedStateFromProps(props, state)
-
shouldComponentUpdate(nextProps, nextState)
decide whether the component should be updated / re-rendered.
It's for performance improvement, prevent useless update
class MyComponent extends Component { shouldComponentUpdate(nextProps, nextState) { if (this.state.person === nextState.person) { return false; } return true; } }In this case, when the
state.personisn't changed, the component will not be updated. So, it's very important that:Always manipulate the copy of state.
-
render()
-
getSnapshotBeforeUpdate(prevProps, prevState)
-
componentDidUpdate()
- call other functions, such as http request
useEffect
useEffect makes functional component accessable to lifecycles:
-
componentDidMount()
-
componentDidUpdate()
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
// http request
});
control useEffect
pass the second param:
useEffect(
() => {},
[props.person]);
That means, ONLY props.person changes, the component can be updated
If you don't want to update component at all, only init component, pass an empty array.
useEffect(
() => {},
[]);
cleanup
Sometime, we need cleanup, like remove event listener.
In lifecycle, there is a function, componentWillUnmout().
useEffect can do cleanup, too.
useEffect(
() => {
return () => { cleanup(); },
}
);
React.memo()
In class-based component, we need shouldComponentUpdate to control the update.
If you want to control the update in Functional Component, use React.memo.
export default React.memo(MyComponent)
It will check if the props is changed.
Be careful of the update check. In a lot of cases, the stateless child component always is updated while its stateful parent component changes. In these cases, the update check is useless.
PureComponent
A common case, we don't update component unless one of the props is updated, we use PureComponent.
class MyComponent extends PureComponent {
// useless codes because PureComponent is extended
// shouldComponentUpdate(nextProps, nextState) {
// if (this.props.a !== nextProps.a ||
// this.props.b !== nextProps.b ||
// this.props.c !== nextProps.c ||
// this.props.d !== nextProps.d ) {
// return true;
// }
// return false
// }
}