Please checkout and subscribe to my video content on YouTube. Feel free to leave comments and suggestions for what content you would like to see.
YouTube Channel
Overview
Simple application with a list of things and the ability to add, edit and delete things. We will use the useReducer
hook to manage the state of the array of things.
We will use the useState
hook to manage the state of the modal dialog we are using to input the information for the thing we are editing or updating and we use the useState
hook to manage the state of the input field in the modal dialog.
Lets Start with the useReducer API
// useThings.js
// --
import React from "react";
const useThings = () => {
// handle the specific action dispatched
const reducer = (state, action) => {
switch (action.type) {
case "ADD_THING": { }
case "DELETE_THING": { }
case "EDIT_THING": { };
default: {
return state;
}
}
};
// here we set things up to use the reducer
const [state, dispatch] = React.useReducer(reducer, {
things: []
});
// the function returns everything needed to the caller to
// dispatch specific action and get the updated state changes
return {
state,
dispatch
};
};
export default useThings;
Modify values in the state
Add An Item: Add the action.data
to the end of the array, set state properties
case "ADD_THING": {
return { ...state, things: [...state.things, action.data] };
}
Deleting An Item: Add the action.index
slice the array to get the things before the thing specified by the index and everything after the item specified by the index. This in turn is used to create new array which we set state.things
with
case "DELETE_THING": {
return {
...state,
things: [
...state.things.slice(0, action.index),
...state.things.slice(action.index + 1)
]
};
}
Editing An Item: Add the action.index
slice the array to get the things before the thing specified by the index and everything after the item specified by the index. Next we use the action.data
as the new element to replace the element that was previously there. This in turn is used to create new array which we set state.things
with.
case "EDIT_THING": {
return {
...state,
things: [
...state.things.slice(0, action.index),
action.data,
...state.things.slice(action.index + 1)
]
};
}
Displaying a Modal for User Input
Using the useState
functionality to manage displaying the modal
dialog for inputting data for new things or editing things. The state has two keys, isVisible
and value
. isVisible
will be set to true to show the dialog and false to hide it. The value
property will be set when we are actually editing an object. We will also add an additional property called index
when editing a thing so we can find it in the state array to update it.
// ThingsList.js
// --
// using the useState functionality to manage displaying the modal
// dialog for inputting data for new things or editing things
const [modalInfo, setModalInfo] = useState({ isVisible: false, value: "" });
Managing the Input Value Using useState
// ThingEdit.js
// --
const [inputValue, setInputValue] = useState();
How we use this in the render
method of the component; when there is an input event in the input element, we update the state with the value entered by the user
<IonInput
value={inputValue}
onInput={e => setInputValue(e.target.value)} />
So when the user is finished in the modal they will click on of two buttons to call the handleClick
method
<IonButton onClick={() => handleClick(true)}>Save</IonButton>
<IonButton onClick={() => handleClick(null)}>Cancel</IonButton>
If handleClick
is called with a true
value, then we need to return the value from the input form which is saved in our state, if the value is passed to handleClick
is null, then we just need to exit the function and not return any data
// ThingEdit.js
// --
const handleClick = _save => {
handleFormSubmit({ isVisible: false, value: _save && inputValue });
};
Back in the ThingsList
component we need to handle the call from the ThingEdit
component to process the data received from the modal.
Get the response from the modal/form so we can update or create a new item. if the _formResponse.value
is empty then ignore because the user selected the cancel button.
If there is a _formResponse.value
& modalInfo.index
has a value, then
edit the item; the modalInfo.index
variable tells us which item in t he array to update; if no modalInfo.index
then create a new things with the _formResponse.value
// ThingsList.js
// --
const handleFormSubmit = _formResponse => {
if (_formResponse.value) {
modalInfo.index != null
? editEntry(modalInfo.index, _formResponse.value)
: addNewEntry(_formResponse.value);
}
// reset the modalInfo state
setModalInfo({ ...modalInfo, isVisible: false, value: "" });
};
Displaying the List Of Things
Rendering the list of things from the components custom hook, useThings
, we mentioned at the start of the post.
// get the function from my custom hook to mange the list
// of things
let { state, dispatch } = useThings();
This give us access to the state object and the state object contains state.things
. We loop through the array of values using the Array.map()
function
<IonList>
{state.things.map((_thing, _index) => (
<IonItem key={_index}>
<IonLabel className="ion-text-wrap">{_thing}</IonLabel>
<IonButton onClick={() => modalInfoWithEntry(_thing, _index)}>
Edit
</IonButton>
<IonButton color="danger" onClick={() => deleteEntry(_index)}>
Delete
</IonButton>
</IonItem>
))}
</IonList>
We have all of the base function that are wrappers for calling the reducer methods with dispatch
// ThingsList.js
//-
/**
* add entry to the list using `dispatch` from custom hook
*/
const addNewEntry = _data => {
dispatch({ type: "ADD_THING", data: _data });
};
/**
* remove entry from the list using `dispatch` and index in the array
* to call custom hook
* @param {*} _index
*/
const deleteEntry = _index => {
dispatch({ type: "DELETE_THING", index: _index });
};
/**
* update an existing entry in the list based on data
* and the index of the entry
* @param {*} _index
* @param {*} _data
*/
const editEntry = (_index, _data) => {
let payload = { index: _index, data: _data };
dispatch({ type: "EDIT_THING", ...payload });
};
Wrapping It All Up
All of the code for this projects in available to you here in the CodeSandbox.io website listed below.
React hooks with useState
and useReducer
allows for your whole application to just be functional components who's state can be managed with the hooks api.
Here is a link to a great video to give you some of the reasons why you might want to give hooks a try in your application.
Top comments (0)