0

I'm trying to learn typescript, currently creating a note taking app. It's very simple: when you click on adding a new note, you a get an empty textarea, where you can edit your note. I'm able to add notes, but I can't update the value of each textarea. What am I doing wrong?

Here's what I have so far:


  const [showSidePanel, setShowSidePanel] = React.useState<boolean>(false);

  const [notes, setNotes] = React.useState([{text: '', id: nanoid()}]);
  const [noteText, setNoteText] = React.useState<string>('');

  const addNote = (): void => {
    const newNote = {text: 'hey', id: nanoid()};
    setNotes([...notes, newNote])
  }

  const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
    setNoteText(event.target.value)
  }

  const toggleSidePanel = React.useCallback(() => setShowSidePanel(!showSidePanel), [showSidePanel]);
  const wrapperRef = React.useRef<HTMLDivElement>(null);
  useClickOutside(wrapperRef, () => setShowSidePanel(false));



  return (
    <div ref={wrapperRef}>
      <GlobalStyle />
      <SidePanel showSidePanel={showSidePanel}>
        <Button onClick={addNote}>Add note</Button>
        {notes.map((n) =>
          <Note onChange={() => handleChange} text={noteText} key={n.id}/>
        )}
      </SidePanel>
      <ToggleButton onClick={toggleSidePanel}>Open</ToggleButton>
    </div>
  );
}
agobago
  • 81
  • 7

1 Answers1

0

If I understand it correctly, each Note is a text-area and you want to update each one of them independently and noteText state is used for active text-area component, correct?

If that's the case then we can either (1)remove noteText state and update notes array directly for appropriate notes.id or (2)we can preserve noteText state and update the notes array after debouncing.

Latter solution is preferable and coded below:

// a hook for debouncing
export const useDebouncedValue = (value, timeOut=500) => {
    const [debouncedValue, setDebouncedValue] = useState(null);
    useEffect(() => {
        let someTimeout;
        someTimeout = setTimeout(() => {
            setDebouncedValue(value);
        }, timeOut);
        return () => clearInterval(someTimeout);
    }, [value, timeOut]);
    return {
        debouncedValue,
    };
};

Main logic for updating the notes array logic

const Comp = () => {
    const [showSidePanel, setShowSidePanel] = React.useState(false);

    const [notes, setNotes] = React.useState([{ text: "", id: nanoid() }]);
    const [currNoteText, setCurrNoteText] = React.useState({
        text: "",
        id: "",
    });
    
    // this always holds the debounced value
    const updatedNoteText = useDebouncedValue(currNoteText.text, 600);

    // effect will get triggered whenever the currNoteText.text is changed and pause of 600ms is taken
    useEffect(() => {
        const notesIndex = notes.findIndex((ele) => ele.id === currNoteText.id);
        if (notesIndex >= 0) {
            const updatedNotes = _.cloneDeep(notes);
            updatedNotes[notesIndex].text = updatedNoteText;
            // updation of notes array
            setNotes(updatedNotes);
        }
    }, [updatedNoteText]);

    const addNote = () => {
        const newNote = { text: "hey", id: nanoid() };
        setNotes([...notes, newNote]);
    };

    const handleChange = (event, noteId) => {
        // setting current changed note in currNoteText Object
        setCurrNoteText({ id: noteId, text: event.target.value });
    };

    const toggleSidePanel = React.useCallback(
        () => setShowSidePanel(!showSidePanel),
        [showSidePanel]
    );
    const wrapperRef = React.useRef(null);
    useClickOutside(wrapperRef, () => setShowSidePanel(false));

    return (
        <div ref={wrapperRef}>
            <GlobalStyle />
            <SidePanel showSidePanel={showSidePanel}>
                <Button onClick={addNote}>Add note</Button>
                {notes.map((n) => (
                    <Note
                        // here along with event we are also passing note-id
                        onChange={(e) => handleChange(e, n.id)}
                        text={noteText}
                        key={n.id}
                    />
                ))}
            </SidePanel>
            <ToggleButton onClick={toggleSidePanel}>Open</ToggleButton>
        </div>
    );
};
Shyam Mittal
  • 188
  • 2
  • 9