P
P
pandycrowl2022-02-21 16:10:42
PostgreSQL
pandycrowl, 2022-02-21 16:10:42

Please rate my first Crud To-do list project on React.js + Node.js + Postgresql?

I created my first React project with server requests. Please rate it, maybe there are some flaws, something is missing or something is superfluous, or in general there is an easier way to implement it. I'll be glad to chat.

app.js

import { useState } from 'react'
import Todoform from './Components/TodoForm'

function App() {
  const [todo, setTodo] = useState([])

  const todoLength = (todos) => {
    if (todos) {
      setTodo(todos)
    }
  }
  return (
    <div className="App">

      <header>
        <h1>Список задач: {todo.length} </h1>
      </header>
      <Todoform todoLength={todoLength} />
    </div>
  );
}

export default App;


TodoForm.js Component
import { useState, useEffect } from 'react'
import ModalInput from './ModalInput';

function Todoform({ todoLength }) {
    const [modalActive, setModalActive] = useState(false)
    const [error, setError] = useState(null)
    const [isLoaded, setIsLoaded] = useState(false)
    const [todos, setTodos] = useState([])
    const [userInput, setUserInput] = useState('')
    const [userInputUpdate, setUserInputUpdate] = useState('')
    const [todo, setTodo] = useState([])
    const [isChecked, setIsChecked] = useState(false);

    const handleOnChange = () => {
        setIsChecked(!isChecked);
    };

    useEffect(() => {
        getTodos()
    }, [])

    const getTodos = () => {
        fetch('http://localhost:3001/api/todo', {
            method: 'GET',
        })
            .then(res => res.json())
            .then(
                (result) => {
                    setIsLoaded(true);
                    setTodos(result);
                    todoLength(result)
                },
                (error) => {
                    setIsLoaded(true);
                    setError(error);
                }
            )
    }
    const createTodo = () => {
        fetch('http://localhost:3001/api/todo', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                todo_text: userInput,
                complete: false
            }),
        })
            .then((res) => res.json())
            .then(result => {
                setTodos([...todos, result])
                getTodos()
            },
                (error) => {
                    setIsLoaded(true)
                    setError(error)
                }
            )
    }
    const updateTodo = (id, todo_text, complete) => {
        fetch(`http://localhost:3001/api/todo`, {
            method: 'PUT',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                todo_text: todo_text,
                complete: complete,
                id: id
            }),
        })
            .then((res) => res.json())
            .then(result => {
                setTodos([...todos])
                getTodos()
            },
                (error) => {
                    setIsLoaded(true)
                    setError(error)
                }
            )
    }
    const removeTodo = (id) => {
        fetch(`http://localhost:3001/api/todo/${id}`, {
            method: 'DELETE',
        })
            .then(data => {
                // alert(data)
                getTodos()
            })
    }
    const handleChange = (e) => {
        setUserInput(e.currentTarget.value)
    }
    const handleSubmit = (e) => {
        e.preventDefault()
        if (userInput) {
            setUserInput('')
            createTodo()
        }
    }
    const handleKeyPress = (e) => {
        if (e.key === 'Enter') {
            handleSubmit(e)
        }
    }
    const handleModalChange = (e) => {
        setUserInputUpdate(e.currentTarget.value)
    }
    const handleModalSubmit = (event) => {
        event.preventDefault()
        if (userInputUpdate) {
            setUserInputUpdate('')
            updateTodo(todo[0], userInputUpdate, isChecked)
            setModalActive(false)
        }

    }
    const handleKeyPressmodal = (e) => {
        if (e.key === 'Enter') {
            handleModalSubmit(e)
        }
    }
    if (error) {
        return <div>Ошибка: {error.message}</div>;
    } else if (!isLoaded) {
        return <div>Загрузка...</div>;
    } else if (todos) {
        return (
            <div>
                <form onSubmit={handleSubmit}>
                    <input
                        className='input'
                        value={userInput}
                        type="text"
                        onChange={handleChange}
                        onKeyDown={handleKeyPress}
                        placeholder="Введите текст"
                    />
                    <button className="item-save">Сохранить</button>
                </form>
                {todos.map((todo) => {
                    return (<div className="todos" >
                        <div key={todo.id} className="item-todo" >
                            <div className={todo.complete ? "item-text strike" : "item-text"} >
                                {todo.todo_text}  {todo.complete}
                            </div>
                            <div className='todo-checkbox'>
                                <input className='checkbox' type="checkbox" checked={todo.complete ? true : false} onChange={() => { updateTodo(todo.id, todo.todo_text, !todo.complete); setIsChecked(!todo.complete) }} />
                            </div>
                        </div>

                        <button className="item-update" onClick={() => { setModalActive(true); setTodo([todo.id, todo.todo_text, todo.complete]); setUserInputUpdate(todo.todo_text); setIsChecked(todo.complete) }}>
                            Изменить
                        </button>
                        <button className="item-delete" onClick={() => removeTodo(todo.id)}>
                            X
                        </button>
                    </div>)
                })}
                <ModalInput active={modalActive} setActive={setModalActive}>
                    <form onSubmit={handleModalSubmit}>
                        <input
                            className='input'
                            value={userInputUpdate}
                            type="text"
                            onChange={handleModalChange}
                            onKeyDown={handleKeyPressmodal}
                            placeholder="Введите текст"
                        />
                        <input className='checkbox' type="checkbox" checked={isChecked ? true : false} onChange={handleOnChange} />
                        <button className="item-save">Сохранить</button>
                    </form>
                </ModalInput>
            </div>
        )
    }
}

export default Todoform


ModalInput.js
const ModalInput = ({ active, setActive, children }) => {
    return (
        <div className={active ? "modal active" : "modal"} onClick={() => setActive(false)}>
            <div className={active ? "modal__content active" : "modal__content"} onClick={e => e.stopPropagation()}>
                {children}
            </div>
        </div>
    )
}

export default ModalInput


Link to full backend project: https://github.com/pandycrowl/Crud-ToDo-List.git And

I have a couple of questions:

with .js extension. I did not understand something, or does it matter what extension?
2. I don't know how to get rid of two warnings: 1) "Warning: Each child in a list should have a unique "key" prop. Check the render method of Todoform." 2) "React Hook useEffect has a missing dependency: 'getTodos'. Either include it or remove the dependency array react-hooks/exhaustive-deps"

Answer the question

In order to leave comments, you need to log in

2 answer(s)
B
black1277, 2022-02-21
@pandycrowl

On questions:
1 There is not much difference, only for your IDE - it will make the hints more correctly in the jsx file
2 The first warning that you use key={todo.id} is a bit wrong - you need to move it to the parent div

<div className="todos" вот сюда>
       <div key={todo.id} className="item-todo" >

the second warning is due to the fact that the hook in its dependency array does not see the function called in it
useEffect(() => {
        getTodos()
    }, [вот тут])

while you can put such a line so as not to see the error
useEffect(() => {
        getTodos()
// eslint-disable-next-line
    }, [])

If you want to understand the correct use of useEffect

B
budda674, 2022-02-21
@budda674

1) asynchronous requests should be wrapped in useMemo or useCallback
2)checked={isChecked ? true : false} abbreviate to checked={isChecked}
3) the list has a key in the wrong place - here the key 4) it is better to use sequelize for queries to the database 5) all information from db.js must be stored in .env 6) it is easier to use package cors 7) to the project, you need to describe the readme with info on how to run it <div className="todos" >

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question