The Gist
I haven't had a chance to implement React's state hooks in a project yet, so I quickly found a tutorial on Scotch.io to dive into.
I wanted to document my journey through the project and questions I hit as I start using hooks.
The Journey
1) Question: First question I had as I built the below code, was on the syntax. Specifically, using useState([])
function App() {
const [todos, setTodos] = useState([
{ text: "Learn about React" },
{ text: "Meet friend for lunch" },
{ text: "Build really cool todo app" }
]);
}
Answer: Just some regular destructuring, which "makes it possible to unpack values from arrays, or properties from objects, into distinct variables."
I was used to object destructuring:
const person = {first: 'Wes'}
const first = person.first; // 'Wes'
But with array destructuring, we don't have to worry about keys and values jumbling up our code. I quickly found a very clear post by Sarah Chima, called Destructuring Assignment in ES6- Arrays.
Two key basic things are that this array destructuring helps in grabbing our elements based on the array's index. And that commas help us skip over elements and grab the next element.
var sentence = ["Kurt", "likes", "programming"];
var [firstWord,, lastWord] = sentence;
console.log(lastWord) // programming
So now, when I map over my todo
array, the first element would look something like:
console.log(todos[0]); // {text: "Learn about React"}
Now, my app is displaying a list of todos
2) Question: How to add items to my list?
const App = () => {
//useState: 2 variables, name them anything.
// firstVar = value || this.state
// secondVar = function to update value || this.setState
const [todos, setTodos] = useState([
{ text: "Learn about React" },
{ text: "Meet friend for lunch" },
{ text: "Build really cool todo app" }
]);
const addTodo = text => {
// spread operaotor = to create a copy of array
// {text} = from TodoForm/form/input type=text
const newTodos = [...todos, { text }]; //needs to be object
setTodos(newTodos);
};
console.log(todos); // {text: "Learn about React"}
return (
<div className="app">
<div className="todo-list">
{todos.map((todo, index) => (
<Todo key={index} index={index} todo={todo} />
))}
<TodoForm addTodo={addTodo} />
</div>
</div>
);
};
Answer: Where does the magic happen? Well first I had to create a TodoForm component. Still dealing with functional components and hooks, I just added the value for my variable, which will be blank at first. An onChange function was added into the input field, which then passes the value to the addTodo
function that we're getting from App's
state hook declaration. And finally we reset the value to be black with our setValue
function call that works in the same way as setState
does within Class components.
import React, { useState } from "react";
const TodoForm = ({ addTodo }) => {
const [value, setValue] = useState("");
const handleSubmit = e => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
className="input"
value={value}
onChange={e => setValue(e.target.value)}
/>
</form>
);
};
export default TodoForm;
Then inside of our app, after importing our TodoForm
component, we pass it the addToDo
function as a prop. Let's take a look at that function. Here I'm pulling in the user's text, which is a property on our input field. I create a variable, and pass in a copy of my todos
array with the spread operator. The second variable in my array is the text we will adding onto our array, and thus our list of tasks.
const addTodo = text => {
// spread operaotor = to create a copy of array
// {text} = from TodoForm/form/input type=text
const newTodos = [...todos, { text }]; //needs to be object
setTodos(newTodos);
};
3) Question: How do I update my list once I've completed a task?
Well most of the work for updating a task as complete is being done in the following callback function, inside my App.js file:
const completedToDo = (index) => {
// array holds copt of task list array
const newTodos = [...todos];
// find item by its index in array
// access the isCompleted property
newTodos[index].isCompleted === false
? (newTodos[index].isCompleted = true)
: (newTodos[index].isCompleted = false);
// set ToDo list to alrered array that was copied
setTodos(newTodos);
};
Answer: It bothered me that I could only mark a task as complete once and not undo it according to the tutorial so I added a ternary to toggle my isCompleted = false
property that I added to all my task objects in their initial state. How this works is a Todo
component is created with the completedToDo
function. This function has access to the index
attribute. My ToDo
component now looks like:
const Todo = ({ todo, index, completedToDo }) => {
// Set variabls to hold me strings here
const complete = "Complete";
const undo = "Undo";
return (
<div
className="todo"
style={{ textDecoration: todo.isCompleted ? "line-through" : "" }}
>
{todo.text}
<div>
<button onClick={() => completedToDo(index)}>
{" "}
{todo.isCompleted ? undo : complete}
</button>
</div>
</div>
);
};
export default Todo;
You can see that I have an onClick even handler that registers when I click a task button, and sends the index up to my completedToDo
function. Depending on whether todo.isCompleted
if flase or true I display different text. Not a huge change, but it makes it feel more like a task list. It's in my completedToDo
function where I'm changing my boolean value. And then I'm using my react hook variable, setTodos
, to update my react hook state.
newTodos[index].isCompleted === false
? (newTodos[index].isCompleted = true)
: (newTodos[index].isCompleted = false);
setTodos(newTodos);
So that's mainly it! Now we have buttons that can be marked as completed, or if we accidentally hit it or realize there was something missing, we can always undo
.
4) Question: How can I delete an item from my list?
Well it's basically a lot like the function I created to mark a task as completed.
const removeTodo = index => {
// create a copy of original array
const newTodos = [...todos];
// use splice() to remove item from array based on it's index
// alters that copy of the array that we've made
newTodos.splice(index, 1);
setTodos(newTodos);
};
Answer: We add this callback at a prop in our ToDo
component, it grabs the index, I create a copy of my todos
array, use the splice()
method to remove an element from our array based on it's index. Then the new array copy with remove elements is set with setTodos
.
And that's pretty much it! Now both you and I understand the basic of using the usState
React Hook to add state to your functional components.
Conclusion
Scotch.io has some great tutorials, sometimes they can be outdated, but for the most part it's a great resource to have. Again, I didn't create this project, but wanted to talk through the parts I need to take a second to research. As you saw, hooks aren't that scary once you jump in! And a big thanks to Sarah Chima, follow her for some more cool walk-troughs and tutorials!
Oh and if you want to take a look at the coded version, I added a link to my CodeSandbox I created. I also advise using that or CodePen, since with the free version you can create an infinite amount of public projects that can be fairly compartmentalized with different files/ NPM packages.
Top comments (0)