Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
May 15, 2021 05:46 am GMT

Create a todo list in React

In this tutorial we will learn how to create a todo list in React using Typescript.

3_app_with_todo_list

Before we create the application, lets set up our development environment.

  1. Download and install the latest stable version of Node

Though Node is not really required to use React, it bundle react applications into a neat packages that can be used relatively easy by other clients. See this stack over flow post for more details

Section 1: Create a react application

Open your terminal and run

npx create-react-app todolist template typescript

Yes, you read it right, npx is a tool for executing node binaries. This stack overflow post describes the differences well

Once you run the above command completes, your project structure should look like this

1_folder_structure

Now you can run your project by doing

npm start

You should see your application running on your default browser at port 3000.

If you have some other application react would ask you to allow it to run on the next availability port

2_initial_run

Congratulations , you have successfully created your first react application.

Apologies if you are already an expert on React

Please commit your code to GitHub or any other code hosting platform. You can refer to this commit for code structure.

In this section, we will build a component to display items in tabular format

Feel free to skip this section by jumping this gist

Section 2.1: Define an interface to represent an item in the todo list

We store the task we are interested in doing as string and its priority as number.

export interface Item {  task: string;  priority: number;}

Section 2.2: Define a component to show the items

This component will receive the items it needs to display through props. Lets call it ToDoList

In the render method we collect the items for props. If there are no items received return a text, Ex: Empty List.

class ToDoList extends React.Component<{ items: Item[] }, {}> {  render() {    const { items } = this.props;    if (items.length === 0) {      return <div>Empty List</div>;    }  }

React.Component takes props as first argument and state as second variable

Since the above component does not involve any user interaction we dont have to store any state. Hence we can ignore the constructor.

If there are any items, we present in tabular format. First create a table with a header.

<table {...getTableStyleProps()}>  <thead>    <tr key={`task_prioirity`}>      <th>Task</th>      <th>Priority</th>    </tr>  </thead></table>

The key property in the row element would be used by React to decide whether this row needs to be re-rendered when there is a change in this component. React docs has a pretty good explanation on keys

Construct the table body by iterating items using map and creating a row

<tbody>  {items.map((i, index) => (    <tr      key={`${i.task}_${i.priority}`}      style={{ backgroundColor: index % 2 === 0 ? "#dddddd" : "white" }}    >      <td>{i.task}</td>      <td>{i.priority}</td>    </tr>  ))}</tbody>

It would be better if we organize our items based on priority. Hence we sort them in ascending order

const sortItems = (items: Item[]): Item[] => {  return items.sort((i1, i2) => i1.priority - i2.priority);};

Stitching everything together we get our ToDoList Component

// ToDoList.tsximport React from "react";export interface Item {  task: string;  priority: number;}const getTableStyleProps = (): {} => {  return {    style: {      width: "100%",      fontFamily: "arial, sans-serif",      borderCollapse: "collapse",      textAlign: "left",      padding: "8px",      border: " 1px solid #dddddd",    },  };};class ToDoList extends React.Component<{ items: Item[] }, {}> {  render() {    const { items } = this.props;    if (items.length === 0) {      return <div>Empty List</div>;    }    const sortedItems = sortItems(items);    return (      <table {...getTableStyleProps()}>        <thead>          <tr key={`task_prioirity`}>            <th>Task</th>            <th>Priority</th>          </tr>        </thead>        <tbody>          {sortedItems.map((i, index) => (            <tr              key={`${i.task}_${i.priority}`}              style={{ backgroundColor: index % 2 === 0 ? "#dddddd" : "white" }}            >              <td>{i.task}</td>              <td>{i.priority}</td>            </tr>          ))}        </tbody>      </table>    );  }}const sortItems = (items: Item[]): Item[] => {  return items.sort((i1, i2) => i1.priority - i2.priority);};export default ToDoList;

Section 3: Add ToDoList to App

Feel free to skip this section by jumping this gist

At this point, we are ready to use the ToDoList component we wrote in the previous subsection.

Import the component and build an initial list of items

import React from "react";import ToDoList, { Item } from "./ToDoList";const initialList = [  {    task: "Pick up Milk",    priority: 1,  },  {    task: "Buy Eggs",    priority: 2,  },  {    task: "Buy Bread",    priority: 3,  },];
  • Extend the App component to accept props and items as state.
  • Pass items received through state to ToDoList component in render method
class App extends React.Component<{}, { items: Item[] }> {  constructor(props: any) {    super(props);    this.state = {      items: initialList,    };  }  render() {    const { items } = this.state;    return (      <div className="App">        <br />        <ToDoList items={items} />      </div>    );  }}

Stitching everything together should give us our App component

// App.tsximport React from "react";import ToDoList, { Item } from "./ToDoList";const initialList = [  {    task: "Pick up Milk",    priority: 1,  },  {    task: "Buy Eggs",    priority: 2,  },  {    task: "Buy Bread",    priority: 3,  },];class App extends React.Component<{}, { items: Item[] }> {  constructor(props: any) {    super(props);    this.state = {      items: initialList,    };  }  render() {    const { items } = this.state;    return (      <div className="App">        <br />        <ToDoList items={items} />      </div>    );  }}export default App;

Running the application by npm start should show a table like below

12_todoList_display

Please remember to commit your changes at this point.

Section 4: Define a component to add a new item

Feel free to skip section by jumping to this gist

This component would contain two text boxes, one for task and another for priority and a button to submit the item. Lets call it AddItem

I sincerely apologize for bad naming, open for feedback on these

For this component we would need to store the input entered by user in a state variable

import React from "react";import { Item } from "./ToDoList";class AddItem extends React.Component<{ addItem: any }, Item> {  constructor(props: any) {    super(props);    this.state = {      task: "",      priority: -1,    };     }

Render the input form in a tabular format

render() {  return (    <table>      <tbody>        <tr key={""}>          <td>Task:</td>          <td>            <input              id="task"              type="text"              placeholder="Enter task here"              onChange={this.setTask}            />          </td>          <td>Priority:</td>          <td>            <input              id="prioity"              type="text"              placeholder="Enter priority here"              onChange={this.setPriority}            />          </td>          <td>            <input id="submit" type="submit" onClick={this.addItem} />          </td>        </tr>      </tbody>    </table>  );}

As you might have already guessed we will use the functions setTask and setPriority to update the state of item.

setTask(evt: any) {  this.setState({    task: evt.target.value,  });}setPriority(evt: any) {  this.setState({    priority: parseInt(evt.target.value),  });}

Once we collected the inputs, we should validate them.

const isValid = (item: Item): boolean => {  return item.task !== "" && item.priority !== -1;};

Now we can submit the item using the function addItem

addItem(evt: any) {  const item = this.state;  if (isValid(item)) {    this.props.addItem(item);  }  this.setState({    task: "",    priority: -1,  });}

The above snippet calls a function addItem on props. This would pass state (or data) to the parent component. In react world this strategy is called Lifting State Up. We do this so that AddItem can be reused to create newer items.

For the above three functions to be available in render method we need to bind to this object in the constructor.

class AddItem extends React.Component<{ addItem: any }, Item> {  constructor(props: any) {    super(props);    this.state = {      task: "",      priority: -1,    };    this.setTask = this.setTask.bind(this);    this.setPriority = this.setPriority.bind(this);    this.addItem = this.addItem.bind(this);  }

Joining everyything together gives us the AddItem component

// AddItem.tsximport React from "react";import { Item } from "./ToDoList";const isValid = (item: Item): boolean => {  return item.task !== "" && item.priority !== -1;};class AddItem extends React.Component<{ addItem: any }, Item> {  constructor(props: any) {    super(props);    this.state = {      task: "",      priority: -1,    };    this.setTask = this.setTask.bind(this);    this.setPriority = this.setPriority.bind(this);    this.addItem = this.addItem.bind(this);  }  setTask(evt: any) {    this.setState({      task: evt.target.value,    });  }  setPriority(evt: any) {    this.setState({      priority: parseInt(evt.target.value),    });  }  addItem(evt: any) {    const item = this.state;    if (isValid(item)) {      this.props.addItem(item);    }    this.setState({      task: "",      priority: -1,    });  }  render() {    return (      <table>        <tbody>          <tr key={""}>            <td>Task:</td>            <td>              <input                id="task"                type="text"                placeholder="Enter task here"                onChange={this.setTask}              />            </td>            <td>Priority:</td>            <td>              <input                id="prioity"                type="text"                placeholder="Enter priority here"                onChange={this.setPriority}              />            </td>            <td>              <input id="submit" type="submit" onClick={this.addItem} />            </td>          </tr>        </tbody>      </table>    );  }}export default AddItem;

Section 5: Add AddItem to App component

Feel free to skip this section by jumping to this gist

AddItem component can be now imported to App

Before adding a new item, we would need to check if it already exists. Lets write a helper function isPartOf that looks if item is present in items.

const isPartOf = (item: Item, items: Item[]): boolean => {  return items.some((it) => it.priority === item.priority);};

Implement addItem using the helper function isPartOf.

  • If item already exists, alert the user
  • Else update the state
addItem(item: Item) {  const { items } = this.state;  if (isPartOf(item, items)) {    alert(`Item with priorirty: ${item.priority} exists`);    return;  }  this.setState({    items: items.concat(item),  });}

We should concatenate the item to the current list, since states are immutable in react

Bind addItem in the App constructor

class App extends React.Component<{}, { items: Item[] }> {  constructor(props: any) {    super(props);    this.state = {      items: initialList,    };    this.addItem = this.addItem.bind(this);  }

Combining all the code parts together should give us our new App component

// App.tsximport React from "react";import AddItem from "./AddItem";import ToDoList, { Item } from "./ToDoList";const initialList = [  {    task: "Pick up Milk",    priority: 1,  },  {    task: "Buy Eggs",    priority: 2,  },  {    task: "Buy Bread",    priority: 3,  },];const isPartOf = (item: Item, items: Item[]): boolean => {  return items.some((it) => it.priority === item.priority);};class App extends React.Component<{}, { items: Item[] }> {  constructor(props: any) {    super(props);    this.state = {      items: initialList,    };    this.addItem = this.addItem.bind(this);  }  addItem(item: Item) {    const { items } = this.state;    if (isPartOf(item, items)) {      alert(`Item with priorirty: ${item.priority} exists`);      return;    }    this.setState({      items: items.concat(item),    });  }  render() {    const { items } = this.state;    return (      <div className="App">        <AddItem addItem={this.addItem} />        <br />        <ToDoList items={items} />      </div>    );  }}export default App;

Your todo list app is ready to used now. Running npm start should bring a window like below

3_app_with_todo_list

Please check this commit for full code.

Congratulations , you have successfully created a todo list in React.

Congratulations

I have also hosted this application on Code Sandbox. Feel free to play with it

Thanks for reading through the entire article. Please reach out with questions, comments and/or feedback.


Original Link: https://dev.to/achukka/create-a-todo-list-in-react-4mp4

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To