Finally, I researched react hooks quickly last week to consider introducing react hooks to the current react project since most components are using a class.
First, I checked all the components to understand which react hook I need to use.
- use
state
- use
lifecycle method
- use
connect
(for redux)
Before dive into useState()
, would like to think about the benefit.
The benefit to introduce hooks
React Hooks allow us to use state
and lifecycle methods with a functional component.
- less code
- more readable
- easy to test
- possibly improve performance
Also, allow us to create custom hooks(useWhatever) that helps to manage state with useState
For example, useFetchData that fetches data from the API.
In terms of redux
, react hooks allow us to extract data from the Redux store state without connect
useSelector()
and useDispatch()
allows us to call an action from a component we want to call.
Things that React Hooks do not support
reactjs.org/docs/hooks-faq.html#do-hooks-cover-all-use-cases-for-classes
In this post, write 3 simple react apps with useState()
from a class component
- counter app
- display input (object)
- display input (array)
code
https://github.com/koji/typescript/tree/master/usestate
counter app by class component
import React from 'react'
interface Props {
}
interface State {
counter: number;
}
export class ClassCounter extends React.Component <Props,State> {
constructor(props:Props) {
super(props);
this.state = {
counter: 0,
}
}
// +1
handleIncrement = () => {
this.setState({
counter: this.state.counter + 1,
});
}
// -1
handleDecrement = () => {
this.setState({
counter: this.state.counter - 1,
});
}
// reset count
handleReset = () => {
this.setState({
counter: 0
});
}
// +10
handleIncrementTen = () => {
this.setState({
counter: this.state.counter + 10,
});
}
render() {
return (
<div>
<h1>class component</h1>
<p>Count {this.state.counter}</p>
<br/>
<button onClick={this.handleIncrement}>increment</button>
<button onClick={this.handleDecrement}>decrement</button>
<button onClick={this.handleReset}>reset</button>
<br />
<button onClick={this.handleIncrementTen}>increment10</button>
</div>
)
}
}
counter app by hooks
import React, { useState } from 'react';
interface Counter {
counter: number;
}
const FCCounter = () => {
const initialValue = () => {
return 0
};
const [counter, setCount] = useState<Counter>(() => initialValue()); // initial value 0
// +1
const handleIncrement = () => {
setCount((prevCount:number) => prevCount + 1);
}
// -1
const handleDecrement = () => {
setCount((prevCount:number) => prevCount - 1);
}
// reset count
const handleReset = () => {
setCount({ counter: initialValue });
}
// +10
const incrementTen = () => {
setCount((prevCount:number) => prevCount + 10);
}
return (
<div>
<h1>class component</h1>
<p>Count {counter.counter}</p>
<br/>
<button onClick={handleIncrement}>increment</button>
<button onClick={handleDecrement}>decrement</button>
<button onClick={handleReset}>reset</button>
<br/>
<button onClick={incrementTen}>increment10</button>
</div>
)
}
export {
FCCounter
}
index.ts
export { ClassCounter } from './ClassCounter';
export { FCCounter } from './FCCounter';
There are 3 differences between a class component and a functional component with useState
functional component is using
useState<Counter>({ counter: initialValue})
instead ofthis.state = {counter: 0,}
functional component is using
setCount({ counter: counter.counter + 1 });
instead ofthis.setState({counter: this.state.counter + 1,});
functional component is using a function instead of a method. In my understanding, this makes testing easier.
display input (object) by class component
import React, { Component } from 'react'
interface State {
firstName: string;
lastName: string;
}
interface Props {}
class ClassObjectDisplay extends Component <Props, State> {
constructor(props: Props) {
super(props);
this.state = {
firstName: '',
lastName: ''
};
}
handleFirstName = (e: React.FormEvent<HTMLInputElement>) => {
this.setState({
firstName: e.currentTarget.value
});
}
handleLastName = (e: React.FormEvent<HTMLInputElement>) => {
this.setState({
lastName: e.currentTarget.value
});
}
render() {
return (
<div>
<h1>class component</h1>
<form>
<input type="text" value={this.state.firstName} onChange={this.handleFirstName} placeholder="your first name" />
<input type="text" value={this.state.lastName} onChange={this.handleLastName} placeholder="your last name" />
</form>
<h3>My Name: {this.state.firstName} {this.state.lastName}</h3>
</div>
)
}
}
export {
ClassObjectDisplay
}
display input (object) by hooks
import React, {useState} from 'react'
interface person {
firstName: string;
lastName: string;
}
const FCObjectDisplay =() => {
const [name, setName] = useState<person>({ firstName: '', lastName: ''});
const handleFirstName = (e: React.FormEvent<HTMLInputElement>) => {
setName((prevName: person) => { ...name, firstName: e.currentTarget.value });
}
const handleLastName = (e: React.FormEvent<HTMLInputElement>) => {
setName((prevName: person) => { ...name, lastName: e.currentTarget.value });
}
return (
<div>
<h1>functional component with hooks</h1>
<form>
<input type="text" value={name.firstName} onChange={handleFirstName} placeholder="your first name" />
<input type="text" value={name.lastName} onChange={handleLastName} placeholder="your last name"/>
</form>
<h3>My Name: {name.firstName} {name.lastName}</h3>
</div>
)
}
export {
FCObjectDisplay
}
In this case, useState's data structure is person
that has firstName and lastName. Their initial values are empty.
useState<person>({ firstName: '', lastName: ''});
This case needs to use spread syntax to set value properly. If don't use spread, setName({})
will only set firstName.
setName({ ...name, firstName: e.currentTarget.value });
You can try this setName({ firstName: e.currentTarget.value });
to check the issue.
The array case is almost the same as above.
https://github.com/koji/typescript/tree/master/usestate/src/components/Array
[Thoughts]
The above samples are using very simple State
so easy to name variables for useState
, but if State
is kind of complicated, probably creating a couple of variables could be good.
I think converting a class component that only uses State
is good as a starting point.
Top comments (1)
This post is just horribly wrong on setting state
every React developer should use call back function when the new state value is referencing the old state, that's the basic