Company logo
  • Jobs
  • Bootcamp
  • About Us
  • For professionals
    • Home
    • Jobs
    • Courses
    • Questions
    • Teachers
    • Bootcamp
  • For business
    • Home
    • Our process
    • Plans
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Calculator

0

161
Views
How can I debounce editor value when the value is managed by parent component?

Editor component

import Editor from '@monaco-editor/react';
import { useDebounce } from './useDebounce';
import { useEffect, useState } from 'react';

type Props = {
  code: string;
  onChange: (code: string) => void;
  disabled?: boolean;
};

export const GraphqlCodeEditor = ({
  onChange,
  code,
  disabled = false,
}: Props) => {
  const [editorValue, setEditorValue] = useState(code);
  const editorValueDebounced = useDebounce(editorValue, 500);

  useEffect(() => {
    onChange(editorValueDebounced);
  }, [editorValueDebounced, onChange]);

  useEffect(() => {
    if (code !== editorValueDebounced) {
      setEditorValue(code);
    }
  }, [code, editorValueDebounced]);

  return (
    <Editor
      options={{
        minimap: { enabled: false },
        autoClosingBrackets: 'always',
        readOnly: disabled,
      }}
      language="graphql"
      value={editorValue}
      onChange={(value) => {
        if (value) {
          setEditorValue(value);
        }
      }}
    />
  );
};

useDebounce hook

import { useEffect, useState } from 'react';

export const useDebounce = <T>(value: T, delay: number) => {
  // State and setters for debounced value
  const [debouncedValue, setDebouncedValue] = useState(value);
  useEffect(
    () => {
      // Update debounced value after delay
      const handler = setTimeout(() => {
        setDebouncedValue(value);
      }, delay);
      // Cancel the timeout if value changes (also on delay change or unmount)
      // This is how we prevent debounced value from updating if value is changed ...
      // .. within the delay period. Timeout gets cleared and restarted.
      return () => {
        clearTimeout(handler);
      };
    },
    [value, delay] // Only re-call effect if value or delay changes
  );
  return debouncedValue;
};

The code prop in the editor component is managed by a parent component. When e.g a user loads a new code snippet it's updated and the editor should load the new value. The editor should also debounce it's value so the onChange() function isn't called on every keypress.

The editor component above results in a loop where the component switches between the previous value and the new every 500ms.

How can I achieve this with the useDebounce hook?

This is closely related to this post I think, however it's using lodash debounce. I was hoping to achieve the same with the useDebounce hook.

7 months ago · Juan Pablo Isaza
1 answers
Answer question

0

The problem was this useEffect()

useEffect(() => {
  if (code !== editorValueDebounced) {
   setEditorValue(code);
  }
}, [code, editorValueDebounced]);

Changing it to this fixed the problem

useEffect(() => {
  setEditorValue(code);
}, [code]);
7 months ago · Juan Pablo Isaza Report
Answer question
Find remote jobs