supersuhyeon / React-TodoList-app

Todo List app using React and PostCSS

Home Page:https://willowy-blancmange-3236fd.netlify.app/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

React TodoList app

ezgif com-gif-maker (46)
Here is the upgraded version of a habit tracker app that I made before. This is an upgraded version of a habit tracker app that I previously made. I was able to practice function-type Components, React hooks and save a data in localstorage with this project.
TodoListApp

Goals of the project

  1. Build Components hierarchy
  2. Practice ReactHooks - useState, useContext for darkmode, useEffect
  3. Use PostCSS and personal opinion for CSS libraries
  4. save data in window.localStorage

Languages

React, PostCSS

Features

1. Build components

reactcomponents

  1. 3 filter states :
  • All - shows all the data based on user's input and whether checkbox is checked or not
  • Active - only unchecked tasks
  • Completed - only checked tasks
  1. Each component represents :
  • App (orange box) : contains the entirety of the project and update filter state
  • Header(red box) : sets filter state based on what user clicked
  • TodoList(blue box) : filters and displays the data collection according to the filter state
  • Todo(turquoise box) : changes the data status based on the checkbox state and deletes the data
  • AddTodo(yellow box) : adds the data based on user's input

2. Practice ReactHooks - useState, useContext for darkmode, useEffect

- useContext
ezgif com-gif-maker (47)
Instead of prop drilling, it is good to use useContext for accessing global data and re-rendering when the global data changes.

How to use

  1. Make a new file and create context
  2. Wrap child components in the context provider and supply the status value
  3. Use the useContext hook in a child component
//DarkModeContext.jsx
const DarkModeContext = createContext(null);

export function DarkModeProvider({ children }) {
  const [darkMode, setDarkMode] = useState(false);
  const toggleDarkMode = () => {
    setDarkMode((darkMode) => {
      return !darkMode;
      updateDarkMode(!darkMode);
    });
  };

  return (
    <DarkModeContext.Provider value={{ darkMode, toggleDarkMode }}>
      {children}
    </DarkModeContext.Provider>
  );

  function updateDarkMode(darkMode) {
    if (darkMode) {
      //true
      document.documentElement.classList.add("dark");
    } else {
      //false
      document.documentElement.classList.remove("dark");
    }
  }

  export const useDarkMode = () => useContext(DarkModeContext);
}
//App.js
const filters = ["all", "active", "completed"];

function App() {
  const [filter, setFilter] = useState(filters[0]);

  return (
    <>
      <DarkModeProvider>
        <Header
          filters={filters}
          filter={filter}
          onFilterChange={(filter) => setFilter(filter)}
        ></Header>
        <TodoList filter={filter}></TodoList>
      </DarkModeProvider>
    </>
  );
}

export default App;
//Header.jsx
export default function Header({ filter, filters, onFilterChange }) {
  const { darkMode, toggleDarkMode } = useDarkMode();
  const handleDarkMode = () => {
    toggleDarkMode();
  };

  return (
    <header className={styles.header}>
      <button onClick={handleDarkMode} className={styles.toggle}>
        {!darkMode && <MdDarkMode></MdDarkMode>}
        {darkMode && <MdLightMode></MdLightMode>}
      </button>
      <ul className={styles.filters}>
        {filters.map((value, index) => {
          return (
            <li key={index}>
              <button
                className={`${styles.filter} ${
                  filter === value && styles.selected
                }`}
                onClick={() => {
                  return onFilterChange(value);
                }}
              >
                {value}
              </button>
            </li>
          );
        })}
      </ul>
    </header>
  );
}
/* index.css */

:root {
  --color-bg-dark: #f5f5f5;
  --color-bg: #fdfffd;
  --color-gray: #d1d1d1;
  --color-text: #22243b;
  --color-accent: #f16e03;
  --color-white: white;
  --color-scrollbar: #aaa7a7;
}

html.dark {
  --color-bg-dark: #1a1c35;
  --color-bg: #22243b;
  --color-grey: #4e4e4e;
  --color-text: #fdfffd;
}

- useEffect
Create lifecycle methods using useEffect

  1. If there is no second parameter then the callback function will render whenever the component renders
  2. If there is a second parameter [state], useEffect's callback function will render once after the component is mounted and whenever [state] updates
  3. If there is a second parameter within the empty array, useEffect's callback function will only render once when the component is mounted
  4. You can execute a function when the component is unmounted using return ()=>{}

ezgif com-gif-maker (48)

useEffect(() => {
  todoRef.current.scrollIntoView({ behavior: "smooth", block: "end" });
}, [todo]); //whenever props.todo is updated, useEffect's callback is executed.

By using useEffect, users can automatically see the latest list that they added without having to manually scroll to the end.

3. Use PostCSS
I have used different CSS libraries across several projects such as PostCSS, styled-components, and tailwindCSS. These are some of my personal observations.

CSS Pros Cons
CSS Module pure CSS use anywhere, independence (no conflict with class names) create each module.css file
Styled Components CSS in JS independence (no conflict with class names) Hard to read (all the logics are in one file), compiled at runtime
Tailwind pure CSS use anywhere, well-organized design system, good for a personal project styling and HTML are mixed

After I used these 3 different CSS libraries, I believe that PostCSS is great for all projects and easy to approach. Tailwind took me some time to understand how to use but I think that it would be good for personal projects or small projects because they can be finished faster due to the organized design system. It was convenient to use styled components because I don't have to go back and forth between different files but I'm worried about performance due to recompiling at runtime. I will use Tailwind for the next project

4. Save data in Local storage
When we use window.localStorage, we can save the key-value across browser sessions. This means that when the user clicks the refresh button, the data that the user inputs will be saved.

How to use

  • window.localStorage.setItem(key,value) - To add key and value
  • window.localStorage.getItem(key) - To read the value
  • Only strings are stored in localStorage. Therefore, to store an object or an array in localStorage, you need to convert the object to a string and store it. JSON.stringify() converts objects and arrays to JSON strings.
  • When you convert JSON strings to objects or arrays, you can use JSON.parse()
//TodoList.jsx
export default function TodoList({filter}){
    const [todos, setTodos] = useState(()=>{return readTodosFromLocalStorage()})

    useEffect(()=>{
        localStorage.setItem('todos',JSON.stringify(todos))
    },[todos])

    return(
        //...codes
    )

    function readTodosFromLocalStorage(){
    const todos = localStorage.getItem('todos')
    return todos ? JSON.parse(todos) : []
}

Reference links

React icons
tailwind docs
React useContext Hook
My Korean Blog for how touse ReactHooks
localStorage
postCSS
dreamcoding
thinking in react

Self-reflection

I think planning out and building a components hierarchy is the most difficult part before coding. It was hard for me to divide components into smaller components at the beginning but after I realized its maintainability and reusability benefits, ideally that each component has only one task, I tried my best to divide components even though it takes a lot of time. While learning and coding in React, I identified the parts of JavaScript's grammar that I could study more and reinforce. Thanks to this React project, I've been posting a lot about Javascript grammar in my blog. Some things I've written about include: array APIs, spread operator, shallow copy concept, and destructuring. I'm hopeful that I can begin thinking in the React way more!

About

Todo List app using React and PostCSS

https://willowy-blancmange-3236fd.netlify.app/


Languages

Language:JavaScript 57.6%Language:CSS 29.9%Language:HTML 12.4%