Both of these hooks do the same thing... but in a different way. What we write for useReducer hook, the same magic is happening 'behind the scenes' for useState (we see only it's result!).
Let's see the example:
1. useState
const[contactName, setContactName] = useState("");
const[contactImage, setContactImage] = useState(null);
const[contactImageUrl, setContactImageUrl] = useState(null);
function handleImageUpload(e) {
const file = e.target.files[0];
const fileName = e.targe.files[0].name;
if(!file) return;
const matchRgx = fileName.match(/\.(jpg|png|jpeg)/);
if (matchRgx != null) {
setContactImageUrl(URL.createObjectURL(e.target.files[0]));
}
else {
setContactImage(null);
setContactImageUrl(null);
}
}
function handleForm(e) {
e.preventDefault();
window.alert("Successfully added a contact!");
}
return (
<div>
<form onSubmit={handleForm}>
<small>Name:</small>
<input
value={contactName}
type='text'
onChange={(e)=> setContactName(e.target.value)}
/>
<small>Image:</small>
<input
type='file'
accept='image/jpeg,image/png,image/jpg'
onChange={handleImageUpload}
/>
<img src={contactImageUrl} />
<button type='submit'>Submit</button>
</form>
</div>
)
}
2. useReducer
const initialFormState = { contactName: '', contactImage:null, contactImageUrl:null };
function reducer(state, action) {
if (action.type === 'setState') {
return {
...state,
[action.field]: action.value
};
} else if (action.type == "ImageUpload") {
return {
...state,
contactImage: action.file,
contactImageUrl: action.url
}
}
return state;
}
const ReducerHook = () => {
const [state, dispatch] = useReducer(reducer, initialFormState);
function handleImageUpload(e) {
const file = e.target.files[0];
const fileName = e.targe.files[0].name;
if(!file) return;
const matchRgx = fileName.match(/\.(jpg|png|jpeg)/);
if (matchRgx != null) {
const imageUrl = URL.createObjectURL(e.target.files[0]);
dispatch({
type:"ImageUpload",
file:e.target.files[0],
url: imageUrl
})
}
else {
dispatch({
type:"ImageUpload",
file:null,
url: null
})
}
}
function handleName(e) {
e.preventDefault();
}
return (
<div>
<form onSubmit={handleName}>
<small>Name:</small>
<input
name="contactName"
value={state.contactName}
type='text'
onChange={(e) => {
dispatch({
type: 'setState',
field: e.target.name,
value: e.target.value
})
}}
/>
<small>Image:</small>
<img src={state.contactImageUrl} />
<input
type='file'
accept='image/jpeg,image/png,image/jpg'
onChange={handleImageUpload}
/>
<button type='submit'>Submit</button>
</form>
</div>
)
}
export default ReducerHook
EXPLANATION:
When using a useState hook, we directly define a setter functions (something, setSomething) and call them for every state we want to track, differently.
However, useReducer has its own setter function which is literally shared among states. That means that we don't need to define more setter functions for every state we want to track. That setter function is called a reducer.
const[state, dispatch] = useReducer(reducer, initialState)
- state is a container will all the data we want to manipulate with
- dispatch is communicating with a reducer function by sending instructions about what should be changed and how
- reducer is the actual function that submits changes
- initialState is an object with all the initial states
Top comments (0)