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.person
isn'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
// }
}