Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div id="root"></div>
              
            
!

CSS

              
                body {
  height: 100vh;
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}
.box {
  width: 250px;
  h1 {
    font-size: 20px;
    margin: 0 0 1rem 0;
  }
}

              
            
!

JS

              
                import React, { useState, useRef, useMemo, useEffect } from "https://esm.sh/react@18";
import ReactDOM from "https://esm.sh/react-dom@18";
import _ from 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm'

// * useDebounce hook
const useDebounce = (callback) => {
  // 변할 수 있는 훅 ref를 선언한다.
  const ref = useRef();

  // 상태가 변하여 함수가 변한다면 ref를 갱신한다. 
  // ref에 들어간 값이 변하더라도 re-rendering이 되지 않는다.
  // 따라서 debounce 또는 throttle이 re-rendering 되지 않는다. 
  useEffect(() => {
    ref.current = callback;
  }, [callback]);

  // debounce 함수를 useMemo 훅에 빈배열의 의존성을 할당해 마운트 될 때 한 번 생성한다. 
  const debouncedCallback = useMemo(() => {
    // func 함수는 마운트 될 때 한 번 생성한다.
    const func = () => {
      // ref는 변할 수 있다. mutable하다. 
      // 위의 useEffect로 인하여 ref.current는 최신의 함수를 바라본다. 
      ref.current?.();
    };

    // debounce 함수는 마운트 될 때 한 번 생성된다. 
    // 하지만 최신의 ref.current 값을 상대 참조하고 있다.
    return _.debounce(func, 2000);
  // useMemo의 의존성은 없다. 마운트 될 때 한 번만 생성된다. 
  }, []);

  return debouncedCallback;
};

// * App
const App = () => {

  // button
  const sendRequest = () => {
    console.log(`✅ Send request`)
  }
  
  const onClick = useDebounce(() => sendRequest())
  
  // input 
  const [value, setValue] = useState('');
  const sendRequestWithState = useDebounce(() => {
    // send request to the backend
    // access to latest state here
    console.log(`✅ Send naive request with: ${value}`);
  });

  const onChange = (e) => {
    const value = e.target.value;
    setValue(value);
    
    sendRequestWithState();
  }
  
  return(
    <div>
      <div className="box">
        <h1>Let's check console.log</h1>
        <button
          onClick={onClick}
          className="button">
            Send Backend button!
        </button>
      </div>
      <div className="box">
        <h1>Input Text </h1>
        <input onChange={onChange} value={value} />
      </div>
    </div>
  );
}

ReactDOM.render(<App />,
document.getElementById("root"))
              
            
!
999px

Console