๊ฐœ๋ฐœ ๊ณต๋ถ€/๋ฐ๋ธŒ์ฝ”์Šค TIL

[ํด๋ผ์šฐ๋”ฉ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—”์ง€๋‹ˆ์–ด๋ง TIL] 240205 - React ๊ธฐ๋ณธ. ๊ฐ„๋‹จํ•œ ์ผ๊ธฐ์žฅ ํ”„๋กœ์ ํŠธ

๊ฐ€์šค์ด 2024. 2. 5. 20:58

Intro


์˜ค๋Š˜์€ React๋กœ ๊ฐ„๋‹จํ•œ ์ผ๊ธฐ์žฅ ๋งŒ๋“ค๊ธฐ ์‹ค์Šต์„ ์‹œ์ž‘ํ–ˆ๋‹ค!!

 

 

์˜ค๋Š˜ ํ•™์Šตํ•œ ๋‚ด์šฉ


React์—์„œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ

์„ธ๋ถ€ ๋ชฉํ‘œ

  • ํ•œ ์ค„ ์ž…๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ
  • ์—ฌ๋Ÿฌ ์ค„ ์ž…๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ
  • ์„ ํƒ ๋ฐ•์Šค ์ž…๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ
  • ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ํ—จ๋“ค๋งํ•˜๊ธฐ

 

๊ธฐ๋Šฅ์ด ๋น„์Šทํ•œ state๋Š” ํ•˜๋‚˜๋กœ ๋ฌถ๊ธฐ

: ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ์ €์žฅํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ด์ „ ์ฝ”๋“œ
import { useState } from 'react';

const DiaryEditor = () => {
  const [author, setAuthor] = useState('์ด๊ฐ€์—ฐ');
  const [content, setContent] = useState('');

  return (
    <div className="DiaryEditor">
      <h2>์˜ค๋Š˜์˜ ์ผ๊ธฐ</h2>
      <div>
        <input
          value={author}
          onChange={(e) => {
            setAuthor(e.target.value);
          }}
        />
      </div>
      <div>
        <textarea
          value={content}
          onChange={(e) => {
            setContent(e.target.value);
          }}
        />
      </div>
    </div>
  );
};

export default DiaryEditor;

 

  • ์ˆ˜์ • ์ฝ”๋“œ
import { useState } from 'react';

const DiaryEditor = () => {
  const [state, setState] = useState({
    author: '',
    content: '',
  });

  const handleChangeState = (e) => {
    setState({
      ...state,
      [e.target.name]: e.target.value,
    });
  };

  return (
    <div className="DiaryEditor">
      <h2>์˜ค๋Š˜์˜ ์ผ๊ธฐ</h2>
      <div>
        <input name="author" value={state.author} onChange={handleChangeState} />
      </div>
      <div>
        <textarea name="content" value={state.content} onChange={handleChangeState} />
      </div>
    </div>
  );
};

export default DiaryEditor;

 

 

 

 


React์—์„œ DOM ์กฐ์ž‘ํ•˜๊ธฐ - useRef

์„ธ๋ถ€ ๋ชฉํ‘œ

  • ์ผ๊ธฐ ์ €์žฅ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ์ž‘์„ฑ์ž์™€ ์ผ๊ธฐ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ž…๋ ฅ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์•„๋‹ˆ๋ผ๋ฉด focus

 

DOM์„ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด React์˜ useRef๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

import { useState, useRef } from 'react';

const DiaryEditor = () => {
  const authorInput = useRef();
  const contentInput = useRef();

  const [state, setState] = useState({
    author: '',
    content: '',
    emotion: 1,
  });

  const handleChangeState = (e) => {
    setState({
      ...state,
      [e.target.name]: e.target.value,
    });
  };

  const handleSubmit = () => {
    if (state.author.length < 1) {
      authorInput.current.focus();
      return;
    }

    if (state.content.length < 5) {
      contentInput.current.focus();
      return;
    }

    alert('์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
  };

  return (
    <div className="DiaryEditor">
      <h2>์˜ค๋Š˜์˜ ์ผ๊ธฐ</h2>
      <div>
        <input ref={authorInput} name="author" value={state.author} onChange={handleChangeState} />
      </div>
      <div>
        <textarea ref={contentInput} name="content" value={state.content} onChange={handleChangeState} />
      </div>
      <div>
        <label>์˜ค๋Š˜์˜ ๊ฐ์ •์ ์ˆ˜: </label>
        <select name="emotion" value={state.emotion} onChange={handleChangeState}>
          <option value={1}>1</option>
          <option value={2}>2</option>
          <option value={3}>3</option>
          <option value={4}>4</option>
          <option value={5}>5</option>
        </select>
      </div>
      <div>
        <button onClick={handleSubmit}>์ผ๊ธฐ ์ €์žฅํ•˜๊ธฐ</button>
      </div>
    </div>
  );
};

export default DiaryEditor;

 

 

 

 


React์—์„œ ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋งํ•˜๊ธฐ

์„ธ๋ถ€ ๋ชฉํ‘œ

  • ๋ฐฐ์—ด์„ ์ด์šฉํ•˜์—ฌ React์—์„œ LIST๋ฅผ ๋ Œ๋”๋ง ํ•ด๋ณด๊ณ  ๊ฐœ๋ณ„์ ์ธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋งŒ๋“ค์–ด๋ณด๊ธฐ

 

์ผ๊ธฐ๋ฆฌ์ŠคํŠธ (DiaryList) ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

: ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฑธ ๊ตฌํ˜„ํ•˜๊ธฐ ์ „์— ๋”๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ฏธ๋ฆฌ ํ…Œ์ŠคํŠธํ•ด ๋ณธ๋‹ค.

import './App.css';
import DiaryEditor from './DiaryEditor';
import DiaryList from './DiaryList';

const dummyList = [
  {
    id: 1,
    author: '์ด๊ฐ€์—ฐ',
    content: '๋‚ ์”จ ํ๋ฆฌ๊ณ  ๋น„์˜ด',
    emotion: 4,
    created_date: new Date().getTime(),
  },
  {
    id: 2,
    author: 'ํ™๊ธธ๋™',
    content: '์˜ค๋Š˜์€ ์ง‘์—์„œ ์ฝฉ๋‚˜๋ฌผ ๋ถˆ๊ณ ๊ธฐ๋ฅผ ํ•ด๋จน์—ˆ๋‹ค. ๋ง›์žˆ์—ˆ๋‹ค.',
    emotion: 3,
    created_date: new Date().getTime(),
  },
  {
    id: 3,
    author: '๊น€๋ฐ”๋ณด',
    content: '์˜ค๋Š˜์€ ๋ฆฌ์•กํŠธ๋ฅผ ๊ณต๋ถ€ํ–ˆ๋‹ค. ์žฌ๋ฐŒ์—ˆ๋‹ค.',
    emotion: 5,
    created_date: new Date().getTime(),
  },
];

function App() {
  return (
    <div className="App">
      <DiaryEditor />
      <DiaryList diaryList={dummyList} />
    </div>
  );
}

export default App;

 

  • state ๋ณ€์ˆ˜ dummyList๊ฐ€ undefined์ผ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด ๊ฐ’ ์ดˆ๊ธฐํ™” (.defaultProps)
DiaryList.defaultProps = {
  diaryList: [],
};

 

  • map์œผ๋กœ ์š”์†Œ๋ฅผ ๋งŒ๋“ค ๋• key๊ฐ’์„ ์ง€์ •ํ•ด ์ค˜์•ผ ํ•œ๋‹ค. (๋˜๋„๋ก id๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ณ  index๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฑด ์ง€์–‘ํ•จ)
const DiaryList = ({ diaryList }) => {
  console.log(diaryList);
  return (
    <div className="DiaryList">
      <h2>์ผ๊ธฐ ๋ฆฌ์ŠคํŠธ</h2>
      <h4>{diaryList.length}๊ฐœ์˜ ์ผ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.</h4>
      <div>
        {diaryList.map((item) => (
          <div key={item.id}>
            <div>์ž‘์„ฑ์ž: {item.author}</div>
            <div>์ผ๊ธฐ: {item.content}</div>
            <div>๊ฐ์ •: {item.emotion}</div>
            <div>์ž‘์„ฑ ์‹œ๊ฐ„(ms): {item.created_date}</div>
          </div>
        ))}
      </div>
    </div>
  );
};

DiaryList.defaultProps = {
  diaryList: [],
};

export default DiaryList;

 

 

 

๊ฒฐ๊ณผ๋ฌผ

 

 

๋งˆ๋ฌด๋ฆฌ


๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฆฌ์•กํŠธ๋กœ ํ™”๋ฉด์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ ๊ฐ™๋‹ค.

๋ฆฌ์•กํŠธ์—์„  DOM์„ document.querySelector๋กœ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  useRef๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ์š”์†Œ๋ฅผ ํ˜ธ์ถœํ•ด์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒŒ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ๋„ ์ข‹๊ณ  ๋ฆฌ์•กํŠธ์˜ ์žฅ์ ์ธ ๊ฒƒ ๊ฐ™๋‹ค.

๋ฆฌ์•กํŠธ๋ฅผ ์ž˜ ํ™œ์šฉํ•ด์„œ ์•ž์œผ๋กœ ๋” ์žฌ๋ฐŒ๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•ด ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.