in Code, Projects

Building a Simple React Todo List and Timer

One of my goals for 2016 was to ship stuff, quite a few things in fact. We’re close to half-way through the year already, but I finally shipped a thing—a simple React todo list!

GitHubProject PageGIF

On Friday, I put some finishing touches on Theodoro (I know—terrible name) a React-based Pomodoro timer and todo list project I’ve been working on. It’s not perfect, and I’m sure there are some improvements I could make. The goal of the project was always to learn about React (with everyone’s first project—a todo list). At this point, I’ve gotten what I wanted out of the project so it’s time to put it out in the wild and move on.

I wanted to breakdown some of the trickier elements I ran into along with some next steps that I’m taking in particular.

Gotchas and Things That Made My Head Hurt

Keeping todo Stateless

I wanted to keep the basic todo component stateless within the application for a few reasons. Mainly, it’s just easier to manage the application when the state is held in just one top-level component. In this case, for the todo list piece, the state was held in todolist.

This created a few different issues. First, the todo items obviously had to be editable after they were created since that’s a pretty basic functionality of a todo list. If todo had state, you could do something like this (grossly simplified):

const Todo = React.createClass( {
	getInitialState() {
	    return {
	        taskValue: ''
	    };
	},

	componentWillMount() {
		this.setState( {
			taskValue: this.props.taskValue
		} );
	},

	onEdit( event ) {
		this.setState( {
			taskValue: event.target.value
		} );
	},

	render: function() {
		return (
			<div className="input-group" >
				<input type="text" className="form-control" value={ this.state.taskValue } disabled={ ! this.props.editing || this.props.completed } onChange={ this.onEdit } />
				// A bunch of other buttons
			</div>
		);
	}
} );

module.exports = Todo;

We have to find a way to get that same effect without using state in our todo component. The solution was to first setup an editTask prop that would handle the actual editing in the parent component todolist. Then, I could pass the event.target.value into that function like so:

const Todo = React.createClass( {
	editTask: function( event ) {
		this.props.editTask( event.target.value );
	},

	render: function() {
		return (
			<div className="input-group" >
				<input type="text" className="form-control" value={ this.state.taskValue } disabled={ ! this.props.editing || this.props.completed } onChange={ this.editTask } />
				// A bunch of other buttons
			</div>
		);
	}
} );

module.exports = Todo;

Now, when I pass in the actual function that does the editing work as the prop editTask to the todo component, I can access the new value and update my todo accordingly.

Determining Which todo Was Being Accessed

When a todo item is checked or a button is clicked, I wanted to update the corresponding todo. Figuring out which todo component was being clicked on turned out to be trickier than expected. In the end, this actually turned out to be pretty simple, and the Facebook folks even have a doc about it. In my case, I just passed in the index value in the .bind() call like this:

<Todo
    onComplete={ this.onComplete.bind( this, i ) }
/>

While I wouldn’t say that everything else was “easy,” it wasn’t too tricky. Here’s an image of the finished product:

Theodoro—A React todo list and Pomodoro Timer

What’s next?

There are tons of additional elements I could add to this specific project:

  • Searching the todo list and surfacing relevant items
  • A prettier UI in general
  • A better indicator when you’ve completed the full list of todos
  • Using the index value as the key for the todo isn’t the best

As I mentioned previously though, I was using this project primarily to learn about React. Moving forward, I’m going to rebuild this project using Redux. Then, I’m going to focus on a few different skills (Redux and working with APIs) on a new project called One Idea Today. The goal is to create a simple app that authenticates with Twitter. Users could login and post a new idea for a product, book, blog post, etc. The ideas could then be filtered by topic. At the end of the day, you have a giant list of potential ideas along with the author. We’ll see how it turns out!

In the meantime, if you have feedback, comments, or questions about the project above, please let me know either in the comments here or on Twitter!

Leave a Thought