A guide for manipulate Array state in a React Application: Techniques for mutating Arrays

Wes Guirra
5 min readDec 30, 2022

This guide provides an overview of some techniques for manipulating array state in a React application. It covers methods for mutating arrays, such as push and splice as well as strategies for immutably updating array state using the Array.from method. Whether you’re a beginner or an experienced React developer, this guide has something for everyone looking to improve their skills with array manipulation in React.

As we already know React is a very powerful ecosystem where we can create dynamic applications, and in some cases we need to deal with Array to accomplish some requirement, for example a To Do app.

Manipulate state Arrays can be a challenging thing in React, and in this post I want to focus on how to deal with Array manipulation using useState hook.

A dynamic list is a list of item that can be changed by the user, we can define the term as a To Do list, where each task will have name and date, and the user can add or remove tasks from it, without affecting other items.

This time I'll use create-react-app, I want to keep simplicity as a priority, so I'll not be using external libraries not even styled-components, but if you will apply this concept to a bigger app, I suggest you to use styled-components, or webpack.

Pre-requisites and previous knowledge:

I'm assuming that you already know something about flex-box and layout with CSS, also how to create a simple project using create-react-app, say that, I'll not explain the configuration and creation of the project.

Here's the list of knowledge necessary:

  • ReactJS (Required)
  • CSS Flex Box (Preferable)
  • JavaScript Arrays (Preferable)

So let's start creating and running the project with the commands:

npx create-react-app dynamic-list-itens
yarn start

Creating the components

Now let's create one component that later we will use to show each item in the list, I'm not explaining the CSS part here, but you can gather it from the repository that I'll leave at the end of this article.

This component will need to trigger two events to the parent, the deletion and edit events, to do that we will create two props onChange and onDelete, also a prop to receive the name of the current task: value.

import React from 'react';

const ListItem = ({ onChange, onDelete, value }) => {
return (
<div className="Item-container">
<input
className="Item-field"
value={value}
onChange={onChange}
/>
<button onClick={onDelete}>Delete</button>
</div>
);
};

export default ListItem;

Then we will create a component to deal with task creation, basically this is an input component that will trigger onSubmit to the parent.

import React, { useState } from 'react';
const NewTaskInput = ({ onSubmit }) => {

const [newItem, setNewItem] = useState('');

function setNewTask({target}) {
setNewItem(target.value);
}

function submit(e) {
e.preventDefault();
onSubmit(newItem);
}

return (
<div>
<form onSubmit={submit}>
<input
className="Todo-input"
placeholder="Type a new task"
onChange={setNewTask}
/>
<button type="submit">
Add
</button>
</form>
</div>
)
};

export default NewTaskInput;

This component keeps an internal state with the input value using setState then passes the value to the parent, note that we are using form, we will do that to be possible to add a task using enter key without the need to define onKeyDown, also we will use preventDefault to avoid page being reloaded after we submit the form.

Now let's create the parent component, which will be responsible to manipulate the array and the state of it, also deletion and update of tasks.

import React, { useState } from 'react'
import './App.css'
import ListItem from './components/ListItem'
import NewTaskInput from './components/NewTaskInput'

const App = () => {
const [tasks, setTasks] = useState([])

function addNewTask(task) {
const itensCopy = Array.from(tasks)
itensCopy.push({id: tasks.length, value: task})
setTasks(itensCopy)
}

function updateTask({target}, index) {
const itensCopy = Array.from(tasks)
itensCopy.splice(index, 1, { id: index, value: target.value })
setTasks(itensCopy);
}

function deleteTask(index) {
const itensCopy = Array.from(tasks)
itensCopy.splice(index, 1)
setTasks(itensCopy)
}

return (
<div className="App">
<div className="App-header">
<NewTaskInput onSubmit={addNewTask} />
{tasks.map(({id, value}, index) => (
<ListItem
key={id}
value={value}
onChange={(event) => updateTask(event, index)}
onDelete={() => deleteTask(index)}
/>
))}
</div>
<div className="Array-preview">
<pre>
{JSON.stringify(tasks, null, 4)}
</pre>
</div>
</div>
)
}

export default App

In the parent component we will declare three new functions: addNewTask, deleteTask and updateTask:

Note that in each function I'm not updating the Array state directly, because I'll be avoiding an important rule of ReactJS, we can't mutate the state directly, so calling push splice directly from state value will not trigger re-renders of React application, to do that we need to update the entire value of the state, so before we update the state, what we will be doing is that every time we will be creating an Array copy from state, update it, then updating the state with the updated copy, we can do that using Array.from.

The Array.from() static method creates a new, shallow-copied Array instance from an iterable or array-like object.

https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/from

Add item

To add new item, we have declared a simple function responsible only to add new tasks to our task list, there we just receive the task from onSubmit event from NewTaskInput, then we create an Array copy of current tasks, we use push method and we use the length of the array as id to create new item, but it can leverage to error saying that items need to be unique when we delete an item and create one just after it, so a good idea is to use uuid library to do that.

The push() method adds one or more elements to the end of an array and returns the new length of the array.

https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/push

Update item

To update a task, we will use the index param to indicate which element we will update using splice method.

The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place. To access part of an array without modifying it, see slice().

https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

Delete item

To delete a task is basically the same of updating, but when using splice we will omit the last param, as we want to remove not update.

Demo

This is the final result.

This is the repository with the source code if you want to see the entire code.

https://github.com/digital-heroes/dynamic-list-itens

What do you think of this list? Can you suggest any areas for improvement? Do you believe it was helpful? Is this a common challenge that we face when starting with React?

I appreciate you come this far, follow me here for more React tips and also clues about challenges of nowadays developers.

Want to Connect?
https://www.linkedin.com/in/wesleyguirra

--

--

Wes Guirra

Desde que me entendo por gente, procuro maneiras de inovar para melhorar o mundo em que vivemos.