Skip to content

Adding Todo Item to Store

The next step would be to handle onClick actions in our application and dispatch actions based on what button/checkbox was clicked/checked.

We will first handle event of adding new items in the list when user clicks "+ Add" button. Lets do that in TodoList.tsx container and then we will pass that function as prop to our ListHeader component.

import { useDispatch } from "react-redux";
import ListHeader from "../components/ListHeader";
import List from "../components/List";
import { addItem } from "../store/actions/todo";

function TodoList() {
    const dispatch = useDispatch();

    const addItemToList = () => {
        dispatch(addItem());
    };

    return (
        <div className="flex justify-center items-center h-screen">
            <div className="shadow-lg rounded-lg w-[500px]">
                <ListHeader
                    addItemToList={addItemToList}
                />
                <List />
            </div>
        </div>
    );
}

export default TodoList;

This will error out since we are passing addItemToList prop to ListHeader component but it is not defined there. Lets define that property and tell our ListHeader component that it should expect addItemToList to be defined when it is initialized.

Also, since we use Typescript, we will define interface for props, so we know what properties ListHeader should expect.

interface ListHeaderInterface {
    addItemToList: React.MouseEventHandler<HTMLButtonElement> | undefined;
}

function ListHeader(props: ListHeaderInterface) {
    return (
        <div className="flex items-center p-8">
                <form className="basis-full group relative">
                    <input
                        className="focus:ring-2 focus:ring-blue-500
                            focus:outline-none w-full text-sm leading-6
                            text-gray-900 placeholder-gray-400
                            rounded-md py-2 px-4 ring-1 ring-gray-200 shadow-sm"
                        type="text"
                        aria-label="Add to list"
                        placeholder="Add to list"
                    />
                </form>
                <button
                    onClick={props.addItemToList}
                    type="button"
                    className="animate-bounce whitespace-nowrap bg-indigo-600
                        text-white text-sm leading-6 font-medium py-2 px-4 ml-2
                        rounded-lg transition ease-in-out delay-0 bg-blue-500
                        hover:-translate-y-1 hover:bg-indigo-500 duration-300"
                >
                    + Add
                </button>
            </div>
    );
}

export default ListHeader;

Okay, we passed the addItemToList prop, and command our button to call that function on every click. But our TodoList.tsx still shows an error? Right?

Because our addItem action expects title to be passed in order to add a new todo item in the list. Now we need to modify our TodoList.tsx so it saves whatever user types in the input field, so it can be sent to our action and added to state.

For that we will use React Hook useState and event onChange on our input. This will basically populate our declared variabled in useState whenever user types something in the input field.

import { useDispatch } from "react-redux";
import ListHeader from "../components/ListHeader";
import List from "../components/List";
import { addItem } from "../store/actions/todo";
import { useState } from "react";

function TodoList() {
    const dispatch = useDispatch();
    const [title, setTitle] = useState<string>("");

    const addItemToList = () => {
        if (!title) return;

        dispatch(addItem(title));
    };

    return (
        <div className="flex justify-center items-center h-screen">
            <div className="shadow-lg rounded-lg w-[500px]">
                <ListHeader
                    addItemToList={addItemToList}
                    title={title}
                    setTitle={setTitle}
                />
                <List />
            </div>
        </div>
    );
}

export default TodoList;

We passed the title value to addItem action whenever button is clicked. Also did some checks that value is not empty, since we do not want todos with no title, right?

We also passed getter title and setter setTitle to our ListHeader as props in order to be able to handle onChange event on input properly and to display the current value in the input field.

Lets modify our ListHeader components interface and props so we get this working.

interface ListHeaderInterface {
    addItemToList: React.MouseEventHandler<HTMLButtonElement> | undefined;
    title: string;
    setTitle: Function;
}

function ListHeader(props: ListHeaderInterface) {
    return (
        <div className="flex items-center p-8">
            <form className="basis-full group relative">
                <input
                    value={props.title}
                    onChange={e => props.setTitle(e.target.value)}
                    className="focus:ring-2 focus:ring-blue-500
                        focus:outline-none w-full text-sm leading-6
                        text-gray-900 placeholder-gray-400
                        rounded-md py-2 px-4 ring-1 ring-gray-200 shadow-sm"
                    type="text"
                    aria-label="Add to list"
                    placeholder="Add to list"
                />
            </form>
            <button
                onClick={props.addItemToList}
                type="button"
                className="animate-bounce whitespace-nowrap bg-indigo-600
                    text-white text-sm leading-6 font-medium py-2 px-4 ml-2
                    rounded-lg transition ease-in-out delay-0 bg-blue-500
                    hover:-translate-y-1 hover:bg-indigo-500 duration-300"
            >
                + Add
            </button>
        </div>
    );
}

export default ListHeader;

Now, when we input something into our input field and click Add button, nothing happens. Why is that?

It works but we do not see the changes, because we never rendered our list from the store, lets do that in the next part.