The Note-Taking App Project in React (Part 1)

You must first complete Getting Started with React before viewing this Lesson

In this last lesson of the course, we will create a note-taking app to apply many React concepts from the previous lessons. With this app, you can create notes and edit/view/delete them.

We will utilize the concepts of hooks, functional components, react-router to switch between pages, React context API to store the notes, and allow updates, edits, and delete. The buttons will have event listeners to detect clicks and perform actions.

By the end, you will learn to organize a proper project structure and understand how the pieces of React work together.

Setting up our project structure

The first step to create any React project is to use the create-react-app tool from the official React team. If you have this tool globally installed, you can run:

create-react-app note-taking-app

Otherwise, you can run this:

npx create-react-app note-taking-app

It will set up the React project with the proper folder structure and install the essential packages like react, react-dom, etc.

All of our source code will live inside the src folder. Inside the src folder, you will find App.js, which will be our root component.

To run the project, type this command:

npm start

It will display a default welcome page. Now our React environment is ready, and we can start coding our Note-taking app.

Setting up the routers

The note-taking app will have different pages and routes. The react-router will handle these all.

1. Install the react-router-dom to our project:

npm install react-router-dom

2. Wrap the App component inside the <BrowserRouter /> to use the routing features.

src/index.js
  import ReactDOM from 'react-dom'
  import './index.css'
  import App from './App'
  import { BrowserRouter } from 'react-router-dom'

    ReactDOM.render(
      <BrowserRouter>
        <App />
      </BrowserRouter>,
    document.getElementById('root')
  )

3. Create a router component for our application.

We will have four routes for this app-

  1. The Root Route(/): To display a form to create a note.
  2. The Notes Route(/notes): All the created notes will be listed on this page.
  3. A note page(/notes/:id): To display a single note for a given :id.
  4. A note edit page(/notes/edit/:id): To open a form to edit the note.

Router code

To create all of these different routes, we need to write the react-router code. So, create a components folder inside src. Inside that, create another folder “router”. Then, create a router.component.jsx file and include this router code:

src/comopnents/router/router.component.jsx

import React, { Component } from 'react'
import { Route, Switch } from 'react-router-dom'
class Router extends Component {
    render() {
        return (
            <div>
                <Switch>
                    <Route path='/' exact>
                        <h1>Route path / </h1>
                    </Route>
                    <Route path='/notes' exact>
                        <h1>Route path /notes</h1>
                    </Route>
                    <Route path='/notes/:id' exact>
                        <h1>Route path /notes/:id</h1>
                    </Route>
                    <Route path='/notes/edit/:id'>
                        <h1>Route path /notes/edit/:id</h1>		
                    </Route>
                </Switch>
            </div>
        )
    }
}
export default Router

Connecting the Router with the root App component.

The router file is just an independent entity here. To use it, we need to import and render this router component in App.js.

src/App.js

import React from 'react'
import './App.css'
import Router from './components/router/router.component'
class App extends React.Component {
    render() {
        return (
            <div className='App'>
                <Router />
            </div>
        )
    }
}
export default App

We have connected the Router component with the App component. Now, if you save your code, the compiler should show the output in the browser.

Try manually changing the browser URLs one by one and check the outputs according to the Router code that we just wrote:

  1. / should render <h1>Route path /</h1>
  2. /notes should render <h1>Route path /notes</h1>
  3. /notes/34 should render <h1>Route path /notes/34</h1>
  4. /notes/edit/22 should render <h1>Route path /notes/edit/22</h1>

Creating the header component to switch between / and /notes routes

The users won’t have to manually update the browser URL to use the app. For that, we will need create a header component to display two links: note and my notes.

So, inside the component folder, create a folder “header” then header.component.jsx inside it and add this code:

src/header/header.component.jsx

import React, { Component } from 'react'
import { Link } from 'react-router-dom'
/* create your header style css in the same header folder */
import './header.styles.css'
import { withRouter } from 'react-router-dom'

class Header extends Component {
    render() {
        const { location } = this.props
        function setActive(path, exact) {
            if (exact) 
return location.pathname === path && 'active'
return location.pathname.startsWith(path) && 'active'
        }
        return (
            <div className='header'>
<Link to='/' className={`link ${setActive('/', true)}`}>
                    Note
                </Link>
<Link to='/notes' className={`link ${setActive('/notes')}`}>
                    My Notes
                </Link>
            </div>
        )
    }
}
export default withRouter(Header)

We have used the Link component to navigate from one Page to another without refreshing the page. The setActive function detects if the current location matches the URL to apply the active green color.

Note: You can write your CSS styling or use the CSS stylesheet from the final project code folder.

Now, import and render the Header component inside the app:

src/App.js

import Header from './components/header/header.component'
/* previous App.js code */
  return (
  <div className='App'>
 	 <Header>
 	 <Router>
  </div>
  )
/* rest of the code including export */

Now clicking on the header links will help you to navigate from one route to another.

Coding the Create Note page

It’s time to replace the “Route path /” output with an actual page component that will display to the user a form to create a note.

Now, create a note.component.jsx file inside pages/note folder. Components that are used in the Router file should be separately stored inside different folder-like pages.

Study and add the following code to the note component which displays a form:

src/pages/note/note.component.jsx

import React, { useState } from 'react'
import './note.styles.css'
const NotePage = props => {
    const [title, setTitle] = useState('')
    const [text, setText] = useState('')
const handleSubmit = e => {
        /* to avoid browser refresh on form submit */
e.preventDefault()
/* we will add functionality later to add notes to the note context */
        history.push('/notes')
}
    return (
        <div>
            <h1>Create a note</h1>
<form className='form' onSubmit={handleSubmit}>
                <input
                    className='form-input'
                    type='text'
                    placeholder='enter note title'
                    value={title}
onChange={e =>setTitle(e.target.value)}
                    required
                />
                <textarea
                    className='form-textarea'
                    placeholder='type your note...'
                    value={text}
onChange={e =>setText(e.target.value)}
                    required
                />
                <input
                    type='submit'
                    className='form-submit'
                    value=‘Save Note'
                />
            </form>
        </div>
    )
}
export default NotePage

The note page will display a form, and a save note button. We have used the form submit handler to handle the creation of notes.

It implements the concept of controlled forms where title and text state values are updated on any form change.

Now go to the Router component and import this NotePage and render it for the “/” route instead of <h1>Route path /</h1>.

src/components/router/router.component.jsx

import NotePage from '../../pages/note/note.component'
//…
<Route path='/' exact>
    <NotePage />
</Route>
//…

Now go to the / path, and the NotePage should be displayed.

Coding MyNotes page

The MyNotes page will display all the notes that we create. Even though we have not added the functionality to create notes, it is helpful to keep our UI and pages ready first.

Coding the NoteItem component

The NoteItem component will be a part of the MyNotes page component. It will be rendered and mapped for every note that is created.

Note Model

In the app, every note will be represented as an object with these properties:

/* {
    id: any positive number – 1, 2, 3,…,
    title: 'title of the note – a string',
    text: 'the text content of the note'
} */ 

NoteItem’s main work is to take this note object and display some UI. We will also add edit and delete buttons.

Code for NoteItem component:

Create a note-item component inside compoents and include the code below:

src/components/note-item/note-item.component.jsx

import './note-item.styles.css'
const NoteItem = props => {
    const { note } = props
    const { id, title, text } = note
    return (
        <div className='note-item'>
            <div className='note-title'>{id}. {title}</div>
            <div className='note-btn-container'>
<button className='note-btn edit-btn'>
                    Edit
                </button>
                <button className='note-btn delete-btn'>
                    Delete
                </button>
            </div>
        </div>
    )
}
NoteItem.defaultProps = { note: { id: '', title: '', text: '' } }
export default NoteItem

Code for MyNotes page:

Now, we can use the NoteItem component inside the MyNotes page. We have created two dummy note objects and passed them to NoteItem.

src/pages/mynotes/mynotes.component.jsx

import React, { Component } from 'react'
import NoteItem from '../../components/note-item/note-item.component'
import './mynotes.styles.css'
function MyNotes() {
    /* dummy note objects */
const note1 = { id: 1, title: 'test 1', text: 'hello world note 1' }
const note2 = { id: 2, title: 'other note', text: 'hello world note 2' }
    return (
        <div>
            <h1>My Notes</h1>
            <div className='note-container'>
                <NoteItem note={note1} />
<NoteItem note={note2} />
            </div>
        </div>
    )
}
export default MyNotes

Right now, we are rendering NoteItem components manually one by one and passing them an object.

Later, the note objects will be stored inside an array in the note context API. We will then use the .map() method to loop through the array and dynamically render the NoteItem components.

What we have done so far

  • Organized our project folder and set up routers.
  • Defined different routes and laid the foundation for our application.
  • Created React components like Header and NoteItem to make them reusable.
  • Created two Page components for the routes / and /notes, namely NotePage and MyNotes page. The router renders the two-page components.

You are now ready to move to part 2 of this project to work with logic and functionality for the app.

The Note-Taking App Project in React (Part 2)

 

 

Back to: React Tutorial > React Projects

Leave a Reply

Your email address will not be published. Required fields are marked *