اذهب إلى المحتوى

السؤال

نشر

لقد انشأت تطبيق ملاحظات الخاص بمسار react في دورة جافا سكريبت لكن استخدمت تايب سكريبت هل كود نظيف او يمكن تحسينه

import { useEffect, useState } from "react";
import Note from "./Components/Note";
import Alert from "./Components/Alert";
function App() {
  interface Notes{
    id: number | null;
    title: string;
    content: string;
  }
  const [notes , setNotes] = useState<Notes[]>(() => {
    const saveNotes = localStorage.getItem('notes');
    return saveNotes ? JSON.parse(saveNotes) : [];
  });


  const [selectedNote , setSelectedNote] = useState<number| null>(null);
  const [title , setTitle] = useState<string>('');
  const [content , setContent] = useState<string >('')
  const [creating , setCreating] = useState<boolean>(false);
  const [editing , setEditing] = useState<boolean>(false);
  const [validationError , setValidationError] = useState<string[]>([]);

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

  useEffect(() => {
    if(validationError.length !==0){
      setTimeout(() => {
        setValidationError([])
      },3000)
    }
  },[validationError])


  const validate = () => {
    const validationError: string[] = []
    let passed = true;

    if(!title){
      validationError.push('الرجاء ادخال عنوان الملاحظة')
      passed = false
    }
    if(!content){
      validationError.push('الرجاءادخال محتوى الملاحظة')
      passed = false
    }
    setValidationError(validationError)
    return passed
  }

  const titleChange = (event: React.ChangeEvent<HTMLInputElement>)  =>  {
    setTitle(event.target.value);
  }
   const contentChange = (event: React.ChangeEvent<HTMLTextAreaElement>)  =>  {
    setContent(event.target.value);
  }

  const addToNoteHandler = () => {
    setCreating(true)
    setEditing(false);
    setTitle('')
    setContent('')
  }
  
  const saveToNoteHandler = () => {
    if((!validate())) return
    const note = {
      id:  Date.now(),
      title: title,
      content: content
    }
    const saveNotes = [...notes , note]
    setNotes(saveNotes)
    setSelectedNote(note.id)
    setCreating(false)
    setTitle('')
    setContent('')

  }

  const  selectNoteHandler   = (noteId:number) => {
    setSelectedNote(noteId)
    setEditing(false)
    setCreating(false)
  }

  const editNoteHandler = () => {
    const note = notes.find(note => note.id === selectedNote);
    setEditing(true)
    setTitle(note?.title || '')
    setContent(note?.content || '')
  }  

  const updateNoteHandler = () => { 
    if((!validate())) return
    const updateNotes = [...notes];
    const noteIndex = updateNotes.findIndex(note => note.id === selectedNote);
    updateNotes[noteIndex] = {
      id: selectedNote,
      title: title,
      content: content
    }
    setNotes(updateNotes);
    setEditing(false);
    setTitle('')
    setContent('')
  }

  const deleteNoteHandler = () => {
    const deleteNotes = [...notes];
    const noteIndex = deleteNotes.findIndex(note => note.id === selectedNote);
    deleteNotes.splice(noteIndex,1)
    setNotes(deleteNotes)
    setSelectedNote(null)
  }

  const deleteAll = () => {
    if( window.confirm('هل انت متأكد بحذف جميع الملاحظات'))
    setNotes([])
    setSelectedNote(null)
  }
  const getAddNote = () => {
    return (
      <div>
        <h2>إضافة ملاحظة جديدة</h2>
        <div>
          <input
            type="text"
            name="title"
            className="form-input mb-30"
            placeholder="العنوان"
            value={title}
            onChange={titleChange}
          />

          <textarea
            rows={10}
            name="content"
            className="form-input"
            placeholder="النص"
            value={content}
            onChange={contentChange}
          />

          <a href="#" className="button green" onClick={saveToNoteHandler}>
            حفظ
          </a>
        </div>
      </div>
    );
  };

  const getPreview = () => {
    if(notes.length === 0){
      return <h2 className="center">لا يوجد ملاحظة</h2>
    }
    else if(!selectedNote){
      return <h2 className="center">الرجاء اختيار ملاحظة</h2>
    }
    const noteShow = notes.find(note => {
      return note.id === selectedNote
    });
    let noteDisplay = (
      <div>
        <h2>{noteShow?.title}</h2>
        <p>{noteShow?.content}</p>
      </div>
    )

    if(editing){
      noteDisplay = (
        <div>
        <h2>تعديل ملاحظة</h2>
        <div>
          <input
            type="text"
            name="title"
            className="form-input mb-30"
            placeholder="العنوان"
            value={title}
            onChange={titleChange}
          />

          <textarea
            rows={10}
            name="content"
            className="form-input"
            placeholder="النص"
            value={content}
            onChange={contentChange}
          />

          <a href="#" className="button green" onClick={updateNoteHandler}>
            تعديل
          </a>
        </div>
      </div>  
      )
    }
    return (
      <div>
        {!editing && 
          <div className="note-operations">
          <a href="#" onClick={editNoteHandler}><i className="fa fa-pencil-alt" /> </a>
          <a href="#" onClick={deleteNoteHandler}><i className="fa fa-trash" /></a>
          <a href="#" onClick={deleteAll}><i className="fa-solid fa-ban"></i></a>
        </div> 
        }
       {noteDisplay}
      </div>
    );
  };



  return (
    <div className="App">
      <div className="notes-section">
        <ul className="notes-list">
      {notes.map(note =>  <Note key={note.id} title={note.title} noteClicked={() => selectNoteHandler(note.id || 0)} active={note.id === selectedNote}/>)}
        </ul>
        <button className="add-btn" onClick={addToNoteHandler}>+</button>
      </div>
      <div className="preview-section">{creating ? getAddNote() : getPreview()}</div>
      {validationError.length !==0 && <Alert validationMassge={validationError}/>}
    </div>
  );
}

export default App;

 

Recommended Posts

  • 0
نشر

أحسنت في ذلك، فيما يخص TypeScript، فالأفضل تعريف الـ Interfaces في ملف منفصل وليكن types.ts أو interfaces.ts في حال إذا ستُستخدم في أكثر من مكان، أو على الأقل خارج الدالة المكونة.

أيضاً، النوع id: number | null غير ضروري بما أنك تستخدم Date.now()، فالملاحظة ستحصل دائمًا على id عند إنشائها، وتستطيع تبسيطه إلى id: number.

الحالة الوحيدة التي تكون فيها القيمة null هي للمتغير selectedNote، وهو ما قمت به بشكل صحيح useState<number| null>(null)، لكن id داخل كائن الملاحظة نفسه لن يكون null أبدًا.

وبالنسبة لتحديد أنواع الدوال، فمعظم الدوال سواء addToNoteHandler و updateNoteHandler لا تحتوي على أنواع محددة للـ  parameters الخاصة بها أو القيمة العائدة منها ، وTypeScript تستنتجها بناءًا على الكود الخاص بالدالة، لكن تحديدها صراحةً يجعل الكود أوضح.

وللعلم بإمكانك إنشاء Hook مخصص وقابل لإعادة الاستخدام لإدارة أي حالة في localStorage كالتالي:

import { useState, useEffect } from 'react';

function useLocalStorage<T>(key: string, initialValue: T): [T, (value: T) => void] {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  const setValue = (value: T) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
}

export default useLocalStorage;

واستخدامه في App.tsx كالتالي:

 import useLocalStorage from './hooks/useLocalStorage';

const [notes, setNotes] = useLocalStorage<Note[]>('notes', []);

 

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...