<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kshitiz mishra </title>
    <description>The latest articles on DEV Community by Kshitiz mishra  (@xitize).</description>
    <link>https://dev.to/xitize</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F234922%2F7947093d-cde4-4a27-9296-4692babe52a1.jpeg</url>
      <title>DEV Community: Kshitiz mishra </title>
      <link>https://dev.to/xitize</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xitize"/>
    <language>en</language>
    <item>
      <title>Todo App with React.js React-Redux and MUI</title>
      <dc:creator>Kshitiz mishra </dc:creator>
      <pubDate>Sun, 22 Sep 2024 18:12:41 +0000</pubDate>
      <link>https://dev.to/xitize/todo-app-with-reactjs-react-redux-and-mui-662</link>
      <guid>https://dev.to/xitize/todo-app-with-reactjs-react-redux-and-mui-662</guid>
      <description>&lt;p&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;br&gt;
React.js, often referred to simply as React, is a JavaScript library for building user interfaces. When you build a user interface with React, you will first break it apart into pieces called components. Then, you will describe the different visual states for each of your components. Finally, you will connect your components together so that the data flows through them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React-Redux&lt;/strong&gt;&lt;br&gt;
React Redux is a library that provides official bindings to connect React components with Redux, a predictable state container for JavaScript applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MUI&lt;/strong&gt;&lt;br&gt;
MUI (formerly known as Material-UI) is a popular React component library that implements Google’s Material Design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhd2fgkmvdgw0n18c0xud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhd2fgkmvdgw0n18c0xud.png" alt="Todo App Screenshot" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set Up Your React App&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app todo-app

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to project directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd todo-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install react-redux&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx install @redux/toolkit react-redux

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install MUI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @mui/material @emotion/react @emotion/styled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can start the development server by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Project folder structures&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfuoisljm0jlr8g956cq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfuoisljm0jlr8g956cq.png" alt="App folder structure" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Files
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;index.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;we will create provider for redux store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\\todo-app\src\index.js

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store/store";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  &amp;lt;Provider store={store}&amp;gt;
    &amp;lt;React.StrictMode&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;
  &amp;lt;/Provider&amp;gt;
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;App.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\todo-app\src\App.js
import "./App.css";
import ButtonAddTodo from "./component/ButtonAddTodo";
import InputTodo from "./component/InputTodo";
import ListTodo from "./component/ListTodo";
import { useDispatch, useSelector } from "react-redux";
import { addTask } from "./store/taskStore";
import { useState } from "react";
import { Container, Snackbar, Stack, Typography } from "@mui/material";

function App() {
  const [inputText, setInputText] = useState("");
  const [showSnack, setShowSnack] = useState(false);
  const todos = useSelector((state) =&amp;gt; state);
  const dispatch = useDispatch();

  return (
    &amp;lt;Container maxWidth={"sm"}&amp;gt;
      &amp;lt;Typography
        variant="subtitle1"
        style={{
          textAlign: "center",
          margin: 24,
          font: "status-bar",
          fontSize: 23,
          color: "slateblue"
        }}
      &amp;gt;
        Todo App
      &amp;lt;/Typography&amp;gt;
      &amp;lt;Stack direction={"row"} spacing={2} style={{ marginBottom: 32 }}&amp;gt;
        &amp;lt;InputTodo inputText={inputText} setInputText={setInputText} /&amp;gt;
        &amp;lt;ButtonAddTodo
          handleAdd={() =&amp;gt; {
            if (inputText.length === 0) {
              setShowSnack(true);
              return;
            }
            dispatch(addTask({ title: inputText }));
            setInputText("");
          }}
        /&amp;gt;
      &amp;lt;/Stack&amp;gt;
      &amp;lt;ListTodo
        todos={todos.slice().reverse()}
        setInputText={setInputText}
        inputText={inputText}
      /&amp;gt;
      &amp;lt;Snackbar
        open={showSnack}
        autoHideDuration={2000}
        onClose={() =&amp;gt; {
          setShowSnack(false);
        }}
        message="Failed to add, please add something to add todo"
      /&amp;gt;
    &amp;lt;/Container&amp;gt;
  );
}

export default App;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;store.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;we create store and add reducer taskReducer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\\todo-app\src\store\store.js
import { configureStore } from "@reduxjs/toolkit";
import { taskReducer } from "./taskStore";

export default configureStore({ reducer: taskReducer });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;taskStore.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;we createSlice ie. immutable state(shallowcopy) just like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice" rel="noopener noreferrer"&gt;slice &lt;/a&gt; does which will be updated by action, passing the initial state and name the slice "task".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createSlice } from "@reduxjs/toolkit";

const initialState = [];

const taskSlice = createSlice({
  name: "task",
  initialState,
  reducers: {
    addTask: (state, action) =&amp;gt; {
      state.push({
        id: state.length + 1,
        title: action.payload.title,
        completed: false
      });
    },
    markTaskToggle: (state, action) =&amp;gt; {
      const todo = state.find((item) =&amp;gt; item.id === action.payload.id);
      if (todo) {
        todo.completed = !todo.completed; //works as still wrapped in proxy.
      }
    },
    deleteTask: (state, action) =&amp;gt; {
      // console.log("id: " + action.payload.id);
      // state.splice(action.payload.id - 1, 1);
      return state.filter((item) =&amp;gt; item.id !== action.payload.id);
    },
    isEditable: (state, action) =&amp;gt; {
      const todo = state.find((item) =&amp;gt; item.id === action.payload.id);
      if (todo) {
        todo.editable = action.payload.editable; //works as still wrapped in proxy.
      }
    },
    saveTask: (state, action) =&amp;gt; {
      const todo = state.find((item) =&amp;gt; item.id === action.payload.id);
      if (todo) {
        todo.title = action.payload.title; //works as still wrapped in proxy.
      }
    }
  }
});

export const { addTask, markTaskToggle, deleteTask, isEditable, saveTask } =
  taskSlice.actions;
export const taskReducer = taskSlice.reducer;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;ButtonAddTodo.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\\todo-app\src\component\ButtonAddTodo.js

import { Button } from "@mui/material";
import { memo } from "react";

const ButtonAddTodo = ({ handleAdd }) =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Button variant="outlined" onClick={handleAdd}&amp;gt;
        Add
      &amp;lt;/Button&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

export default memo(ButtonAddTodo);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;InputTodo.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\todo-app\src\component\InputTodo.js
import { useDispatch } from "react-redux";
import { addTask } from "../store/taskStore";
import { TextField } from "@mui/material";

const InputTodo = ({ inputText, setInputText }) =&amp;gt; {
  const dispatch = useDispatch();

  const handleInput = (e) =&amp;gt; {
    setInputText(e.target.value);
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;TextField
        variant="outlined"
        aria-label="Todo"
        style={{ flex: 1 }}
        value={inputText}
        onChange={handleInput}
        placeholder="Todo.."
        onKeyUp={(e) =&amp;gt; {
          if (e.key === "Enter") {
            dispatch(addTask({ title: inputText }));
            setInputText("");
          }
        }}
      /&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

export default InputTodo;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;ListTodo.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\todo-app\src\component\ListTodo.js
import { useDispatch } from "react-redux";
import {
  deleteTask,
  markTaskToggle,
  isEditable,
  saveTask
} from "../store/taskStore";
import { Button, Checkbox, Stack, TextField, Typography } from "@mui/material";
import { useRef, useState } from "react";

const ListTodos = ({ todos }) =&amp;gt; {
  const dispatch = useDispatch();
  const [editText, setEditText] = useState("");
  const editEnabledIdRef = useRef(null);

  function handleSave(item) {
    dispatch(saveTask({ id: item.id, title: editText }));
    dispatch(isEditable({ id: item.id, isEditable: false }));
  }

  return (
    &amp;lt;&amp;gt;
      {todos.map((item) =&amp;gt; {
        return (
          &amp;lt;Stack direction={"row"} key={item.id} spacing={2} padding={1}&amp;gt;
            &amp;lt;Checkbox
              aria-label={"label " + item.title}
              checked={item.completed}
              onChange={() =&amp;gt; {
                console.log("item id " + item.id);
                dispatch(markTaskToggle({ id: item.id }));
              }}
            /&amp;gt;
            {item.editable ? (
              &amp;lt;TextField
                onKeyUp={(e) =&amp;gt; {
                  if (e.key === "Enter") {
                    handleSave(item);
                  }
                }}
                value={editText}
                onChange={(e) =&amp;gt; {
                  setEditText(e.target.value);
                }}
                onDoubleClick={() =&amp;gt; {
                  dispatch(isEditable({ id: item.id, editable: false }));
                }}
                variant={"outlined"}
                placeholder={item.completed ? &amp;lt;s&amp;gt;{item.title}&amp;lt;/s&amp;gt; : item.title}
                style={{
                  flex: 1,
                  alignSelf: "center"
                }}
              /&amp;gt;
            ) : (
              &amp;lt;Typography
                variant="subtitle2"
                style={{
                  flex: 1,
                  alignSelf: "center",
                  fontSize: 16,
                  paddingLeft: 12
                }}
                onDoubleClick={() =&amp;gt; {
                  if (editEnabledIdRef.current) {
                    dispatch(
                      isEditable({
                        id: editEnabledIdRef.current,
                        editable: false
                      })
                    );
                  }
                  dispatch(isEditable({ id: item.id, editable: true }));
                  editEnabledIdRef.current = item.id;
                  setEditText(item.title);
                }}
              &amp;gt;
                {item.completed ? &amp;lt;s&amp;gt;{item.title}&amp;lt;/s&amp;gt; : item.title}
              &amp;lt;/Typography&amp;gt;
            )}
            {item.editable ? (
              &amp;lt;Button
                variant="outlined"
                size="small"
                onClick={() =&amp;gt; {
                  handleSave(item);
                }}
              &amp;gt;
                Save
              &amp;lt;/Button&amp;gt;
            ) : (
              &amp;lt;Button
                variant="outlined"
                size="small"
                onClick={() =&amp;gt; {
                  dispatch(deleteTask({ id: item.id }));
                }}
              &amp;gt;
                Delete
              &amp;lt;/Button&amp;gt;
            )}
          &amp;lt;/Stack&amp;gt;
        );
      })}
    &amp;lt;/&amp;gt;
  );
};

export default ListTodos;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/xitize/todo-app" rel="noopener noreferrer"&gt;Github code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>mui</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
