โœ๏ธ TIL

์œ ๋ฐ๋ฏธ ์ทจ์—…๋ถ€ํŠธ์บ ํ”„ - ํ”„๋ก ํŠธ์—”๋“œ&๋ฐฑ์—”๋“œ : 12์ผ์ฐจ TIL

Yuuuki 2023. 12. 30. 17:38

์ด์–ด์ œ์— ์ด์–ด์„œ ๋ฆฌ์•กํŠธ ํ•™์Šต์„ ํ•˜์˜€๋‹ค!

๋‹จ๊ธฐํŠน๊ฐ• ์ฝ”์Šค๋กœ ๋“ฃ๋‹ค๋ณด๋‹ˆ, ํ•™์Šต์˜ ์–‘์ด ์ข€ ๋งŽ์•˜๋‹ค!

 


 

์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง

๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง์„ ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ง€๊ธˆ๊ณผ ๊ฐ™์ด true ๊ฒฝ์šฐ์—๋งŒ ๋ Œ๋”๋งํ• ๋•, &&์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค!

3ํ•ญ ์—ฐ์‚ฐ์ž

{ModalIsVisible ? (
        <Modal onClose={hideModalHandler}>
          <NewPost
            onBodyChange={bodyChangeHandler}
            onAuthorChange={authorChangeHandler}
          />
        </Modal>
      ) : null}

false์ผ๋• null

 

&&์—ฐ์‚ฐ์ž

{ModalIsVisible && (
        <Modal onClose={hideModalHandler}>
          <NewPost
            onBodyChange={bodyChangeHandler}
            onAuthorChange={authorChangeHandler}
          />
        </Modal>
      )}

 

๋ณ€์ˆ˜ ์‚ฌ์šฉ

let modalContent;
  if (ModalIsVisible) {
    modalContent = (
      <Modal onClose={hideModalHandler}>
        <NewPost
          onBodyChange={bodyChangeHandler}
          onAuthorChange={authorChangeHandler}
        />
      </Modal>
    );
  }

  return (
    <>
      {modalContent}
      <ul className={classes.posts}>
        <Post author={enteredAuthor} body={enteredBody} />
        <Post author="Manuel" body="Check out the full course!" />
      </ul>
    </>
  );
}

๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ด€๋ฆฌํ• ๋•Œ, ์ข€ ๋” ํšจ์œจ์ ์ธ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์ง€๋งŒ ์ง€๊ธˆ๊ณผ ๊ฐ™์ด ๋‹จ์ˆœํ•œ ๊ฒฝ์šฐ์—๋Š” ์ง€์–‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

 

useState์˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜

 

const [posts, setPosts] = useState([]);

  function addPostHandler(postData) {
    setPosts([postData, ...posts]);
  }

 

setCount((prevCount) => prevCount + 1);

 

ํ˜„์žฌ ์ƒํƒœ์˜ ์Šค๋ƒ…์ƒท์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค!

๊ทธ๋ฆฌ๊ณ , return ๊ฐ’์œผ๋กœ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผํ•œ๋‹ค.

 

๋ฆฌ์•กํŠธ๋Š” ๋‚ด๋ถ€์—์„œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋ฅผ ๋ฐ”๋กœ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , ์˜ˆ์•ฝํ•ด๋‘๋Š” ๊ฒƒ์ด๋ผ๊ณ  ํ•œ๋‹ค!

๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ ์—…๋ฐ์ดํŠธ๊ฐ€ ์—‰์ผœ์„œ ์ž˜๋ชป๋œ ์ƒํƒœ๋ฅผ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ฆฌ์•กํŠธ๊ฐ€ ์ตœ์‹ ๋ฒ„์ „์˜ ์œ ํšจ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์™€ ์ œ๋Œ€๋กœ ๊ฐฑ์‹ ํ•˜๋„๋ก ํ•ด์ค€๋‹ค.

 

SPA & Router

 

SPA

React๋ฅผ ์‚ฌ์šฉํ•œ ๋‹จ์ผ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(Single Page Application, SPA)์€ ์ „ํ†ต์ ์ธ ๋‹ค์ค‘ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ, SPA๋Š” ํ•˜๋‚˜์˜ HTML ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋กœ๋“œํ•˜์ง€ ์•Š๊ณ  ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๋™์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

 

Router

 

๋ฆฌ์•กํŠธ SPA์—์„œ๋Š” ๊ฒฝ๋กœ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ทฐ๋ฅผ ๋„์šด๋‹ค. ์ด๋•Œ ๋ผ์šฐํŒ…์˜ ๊ฐœ๋…์„ ์‚ฌ์šฉํ•œ๋‹ค.

๋ผ์šฐํŒ…์€ ๋‹ค๋ฅธ ์ฃผ์†Œ์— ๋”ฐ๋ผ ๊ฐ ๋‹ค๋ฅธ ๋ทฐ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ , ๊ฒฝ๋กœ์— ๋”ฐ๋ผ ๋ณ€ํ™˜ํ•ด์ค€๋‹ค.

์ฆ‰, SPA๋ผ๊ณ  ํ•˜์ง€๋งŒ ๊ฐ ๋‹ค๋ฅธ ๋ทฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ , ๊ฐ ๋‹ค๋ฅธ ์ฃผ์†Œ๋ฅผ ๋ถ€์—ฌํ•˜๊ณ  ๊ฒฝ๋กœ ๋ณ€๊ฒฝ์œผ๋กœ์จ ๋‹ค๋ฅธ ๋ทฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š”๊ฒƒ!

 

 

const router=createBrowerRouter([
  {path:'/', 
  element:<RootLayout/>, 
  children:[
    {path:'/',
    element:<Posts/>,
    children:[
      {path:'/create-post',element:<NewPost/>}
    ]}
  ]}
])


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <RouterProvider router={router}/>
  </React.StrictMode>
);

createBrowerRouter๋กœ ๋งŒ๋“  ๋ผ์šฐํŒ…์„ RouterProver์˜ ์†์„ฑ์— ๋„ฃ์–ด render์•ˆ์— ๋„ฃ์–ด์ค€๋‹ค!

 

 

 

Fetch

fetch() ํ•จ์ˆ˜๋Š” ์›น API๋กœ, ๋„คํŠธ์›Œํฌ ๋ฆฌ์†Œ์Šค๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์š”์ฒญํ•˜๊ณ  ์‘๋‹ต์„ ๋‹ค๋ฃจ๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, AJAX ์š”์ฒญ์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” Promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

fetch(url, options)
  .then(response => {
    // ์‘๋‹ต์„ ์ฒ˜๋ฆฌ
    return response.json(); // ๋˜๋Š” response.text(), response.blob() ๋“ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
  })
  .then(data => {
    // ์ฒ˜๋ฆฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉ
  })
  .catch(error => {
    // ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌ
  });

 

(๋งค๊ฐœ๋ณ€์ˆ˜)

  • url: ์š”์ฒญ์„ ๋ณด๋‚ผ URL์ž…๋‹ˆ๋‹ค.
  • options: ์„ค์ • ๊ฐ์ฒด๋กœ, ์š”์ฒญ์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ ์˜ต์…˜์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ, ํ—ค๋”, ๋ฐ”๋”” ๋“ฑ์ด ์—ฌ๊ธฐ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
    • method: HTTP ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ "GET"์ž…๋‹ˆ๋‹ค.
    • headers: ์š”์ฒญ ํ—ค๋”๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฐ์ฒด
    • body: ์š”์ฒญ์˜ ๋ฐ”๋”” ์ง€์ •.  (๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ๋Š” JSON.stringify()๋ฅผ ์‚ฌ์šฉํ•ด JSON๋กœ ํฌ๋งทํ•ด์„œ ๋ณด๋‚ธ๋‹ค)
    • mode: ์š”์ฒญ ๋ชจ๋“œ ์ง€์ •. ("cors", "no-cors", "same-origin" ๋“ฑ์ด ๊ฐ€๋Šฅ)

 

POST: ์„œ๋ฒ„๋กœ ์š”์ฒญ ๋ณด๋‚ด๊ธฐ

function addPostHandler(postData) {
    fetch("http://localhost:8080/posts", {
      method: "POST",
      body: JSON.stringify(postData), //json์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์š”์ฒญ
      headers: {
        "Content-Type": "application/json",
      },
    });
    setPosts([postData, ...posts]);
  }

server

๋ฐฑ์—”๋“œ์—์„œ ์ •๋ณด๋ฅผ ๋ฐ›์•„ ํŒŒ์ผ์— ์ €์žฅํ•œ๋‹ค.

 

 

GET: ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ data ๋ฐ›์•„์˜ค๊ธฐ

Promise ๊ฐ์ฒด

Promise๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด๋กœ, ๋น„๋™๊ธฐ ์ž‘์—…์€ ์ฃผ๋กœ ๋„คํŠธ์›Œํฌ ์š”์ฒญ, ํŒŒ์ผ ์ฝ๊ธฐ, ํƒ€์ด๋จธ ๋“ฑ๊ณผ ๊ฐ™์ด ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์„ ์˜๋ฏธํ•œ๋‹ค.

Promise๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจ์™€ ๊ฐ™์€ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

 

  • ๋Œ€๊ธฐ(pending): ์ดˆ๊ธฐ ์ƒํƒœ๋กœ, ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์„ฑ๊ณตํ•˜๊ฑฐ๋‚˜ ์‹คํŒจํ•  ๋•Œ๊นŒ์ง€์˜ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
  • ์ดํ–‰(fulfilled): ๋น„๋™๊ธฐ ์ž‘์—…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์–ด ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
  • ๊ฑฐ๋ถ€(rejected): ๋น„๋™๊ธฐ ์ž‘์—…์ด ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
const fetchData = () => {
  return new Promise((resolve, reject) => {
    // ๋น„๋™๊ธฐ ์ž‘์—… ์ˆ˜ํ–‰ (์˜ˆ: ๋„คํŠธ์›Œํฌ ์š”์ฒญ)
    const data = /* ... */;
    
    // ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋œ ๊ฒฝ์šฐ
    if (data) {
      resolve(data);
    } else {
      // ์‹คํŒจํ•œ ๊ฒฝ์šฐ
      reject('Error fetching data');
    }
  });
};

// ํ”„๋กœ๋ฏธ์Šค ์‚ฌ์šฉ
fetchData()
  .then(result => {
    console.log('Success:', result);
  })
  .catch(error => {
    console.error('Error:', error);
  });

resolve์™€ reject๋Š” ํ”„๋กœ๋ฏธ์Šค์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜๋กœ,

์„ฑ๊ณต ์‹œ resolve๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ดํ–‰ ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ , ์‹คํŒจ ์‹œ reject๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๊ฑฐ๋ถ€ ์ƒํƒœ๋กœ ๋งŒ๋“ ๋‹ค.

 

 

useEffect

React Hook ์ค‘ ํ•˜๋‚˜๋กœ, ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ถ€์ˆ˜ ํšจ๊ณผ(side effects)๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

๋ถ€์ˆ˜ ํšจ๊ณผ๋ž€ ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ์ž‘์—…์„ ๋งํ•˜๋ฉฐ, ์ฃผ๋กœ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ, ๊ตฌ๋… ์„ค์ •, ์ˆ˜๋™์œผ๋กœ DOM ์กฐ์ž‘ ๋“ฑ์ด ํ•ด๋‹น๋œ๋‹ค.

fetch("http://localhost:8080/posts")
    .then((response) => response.json())
    .then((data) => setPosts(data.posts));


//server return ๊ฐ’
//res.json({ posts: storedPosts });

๊ฐ•์˜์—์„œ ์ด์™€ ๊ฐ™์€ ์˜ˆ์‹œ๋ฅผ ๋“ค๋ฉด์„œ, useEffect๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ์„ค๋ช…ํ•ด์คฌ๋‹ค.

ํ•ญ์ƒ useEffect๋ฅผ  ์ •ํ™•ํžˆ ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š”์ง€ ์ •ํ™•ํžˆ ์ž˜ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์˜€๋Š”๋ฐ ์ด์ฐธ์— ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค!

 

์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ์—์„œ fetch๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ setPosts(์ƒํƒœ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜)๋กœ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ ์ž ํ•œ๋‹ค.

 

๐Ÿค” ์™œ ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋ ๊นŒ?? 

 

๐Ÿ’ก

์ƒํƒœ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ์ƒํƒœ๋กœ ๊ฐฑ์‹  → ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰ → (ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜์–ด) fecth ์š”์ฒญ ๋‹ค์‹œ ๋ณด๋‚ด๊ณ , ๋ฐ์ดํ„ฐ ๋ฐ›๊ณ , ์ƒํƒœ ๊ฐฑ์‹ ํ•˜๊ณ ...? → ๊ฐ™์€ ๋™์ž‘ ๋ฌดํ•œ ๋ฐ˜๋ณต...!!!

 

useEffect๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด?

useEffect๊ฐ€ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์—์„œ sideEffect๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์ผ์œผํ‚ค๊ธฐ ๋•Œ๋ฌธ์—, ์ˆ˜ํ–‰ํ•˜๋ ค๋Š” ๋™์ž‘์ด JSX์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๊ณ , ๋‚˜์ค‘์— ๊ฐ„์ ‘์ ์œผ๋กœ ์˜ํ–ฅ์„ ์ฃผ๊ฑฐ๋‚˜ UI์˜ ๋‹ค๋ฅธ์ž‘์—…์„ ํ•˜๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฌดํ•œ๋ฃจํ”„ ์—†์ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

 

useEffect(() => {
  // ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ
  // ...

  // ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ์ •๋ฆฌํ•˜๋Š”(clean-up) ์ฝ”๋“œ (์˜ต์…˜)
  return () => {
    // ์ •๋ฆฌ ์ฝ”๋“œ
    // ...
  };
}, [dependencies]);

 

(๋งค๊ฐœ๋ณ€์ˆ˜)

  • ์ฝœ๋ฐฑ ํ•จ์ˆ˜: useEffect์˜ ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋˜๋Š” ํ•จ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํŒ๋‹จ๋ ๋•Œ, ์•Œ์•„์„œ ์‹คํ–‰๋œ๋‹ค!
  • ์˜์กด์„ฑ ๋ฐฐ์—ด (dependencies): ๋‘ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋˜๋Š” ๋ฐฐ์—ด์€ useEffect๊ฐ€ ์˜์กดํ•˜๋Š” ๊ฐ’๋“ค์˜ ๋ชฉ๋ก์ด๋‹ค. ์ด ๋ฐฐ์—ด์— ํฌํ•จ๋œ ๊ฐ’๋“ค ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋ณ€๊ฒฝ๋˜๋ฉด useEffect๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. (๋นˆ ๋ฐฐ์—ด[]์€ , useEffect๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋งˆ์šดํŠธ๋  ๋•Œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰)
    ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์™€ ํ•จ๊ป˜ ์‹คํ–‰๋˜์–ด์•ผํ•  ๋•Œ ์‚ฌ์šฉ!
  • ์ •๋ฆฌ(clean-up) ํ•จ์ˆ˜: useEffect ์•ˆ์—์„œ ๋ฐ˜ํ™˜๋œ ํ•จ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋˜๊ฑฐ๋‚˜ ์˜์กด์„ฑ ๋ฐฐ์—ด์— ์žˆ๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ถ€์ˆ˜ ํšจ๊ณผ์—์„œ ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ •๋ฆฌํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋…์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

useNavigate

 

 

<a>์ฒ˜๋Ÿผ ํด๋ฆญ์‹œ url์„ ์ด๋™ํ•˜๋Š”๊ฒƒ์€ Link ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, 

์œ„ ์˜ˆ์‹œ๊ฐ™์ด ๋ชจ๋‹ฌ<div> ํด๋ฆญ์‹œ ์ด๋ฒคํŠธํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜์— useNavigate hook์„ ์‚ฌ์šฉํ•ด ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค

 

 

loader(): ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

loader ํ”„๋กœํผํ‹ฐ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ’์œผ๋กœ ๋ฐ›๊ณ , react-router๋Š” ํ•ด๋‹น ๋ผ์šฐํ„ฐ๊ฐ€ ํ™œ์„ฑํ™” ๋ ๋•Œ(๋ Œ๋”๋ง)๋งˆ๋‹ค loader์— ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

-> ๋ผ์šฐํŠธ ์ปดํฌ๋„ŒํŠธ(ํ•˜์œ„ํฌํ•จ)์—๊ฒŒ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•ด๋‘˜ ์ˆ˜ ์žˆ๋‹ค.

 

โ—๏ธ ๋น„๋™๊ธฐํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด๋„๋˜์ง€๋งŒ, promise๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค๋ฉด promise๊ฐ’์„ ๋ฐ›์„๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค.

 

export async function loader() {
  const response = await fetch("http://localhost:8000/posts");
  const resData = await response.json();
  return resData.posts;
}

(๋ณดํ†ต ํ•ด๋‹น component์— loaderํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑ)

 

์ปดํฌ๋„ŒํŠธ ๋ฐ”๊นฅ์—์„œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํฌ๋„ŒํŠธ ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š์•„ useEffect๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„๋œ๋‹ค!

ํ™”๋ฉด์— ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด , ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜„์žฌ ๋ผ์šฐํŠธ์— ๋ Œ๋”๋ง๋œ ์š”์†Œ๊ฐ€ ๋ฐ›๋Š”๋‹ค.

 

import Posts,{loader as postsLoader} from './routes/Posts'
import NewPost,{action as newPostAction} from './routes/NewPost'
import PostDetails,{action as postDetailLoader} from './routes/PostDetails'

const router=createBrowerRouter([
  {path:'/', 
  element:<RootLayout/>, 
  children:[
    {path:'/',
    element:<Posts/>,
    loader: postsLoader
    children:[
      {path:'/create-post',element:<NewPost/> action:newPostAction }
      {path:'/:id',element:<PostDetails/> loader:postDetailLoader}
      
    ]}
  ]}
])

loader()์—์„œ ๋ฐ˜ํ™˜ํ•œ ๋ฐ์ดํ„ฐ๋Š” Posts ์ปดํฌ๋„ŒํŠธ& ์ค‘์ฒฉ๋œ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ๋œ๋‹ค.

 

loader์˜ ๊ฐ์ฒด request, params๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ์šฐํŠธ์˜ id์— ๊ฐ€์ ธ์˜ฌ์ˆ˜์žˆ๋”ฐ

 

useLoaderData

์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ loader()์—์„œ ๋ฐ˜ํ™˜ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐธ์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ‘‰๐Ÿป ๋‚ด๋ถ€ PostList์˜ (useEffect์˜)fetch๋ถ€๋ถ„๊ณผ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ state, loading์ƒํƒœ ๊นŒ์ง€ ๋ชจ๋‘ ์ง€์›Œ๋ฒ„๋ฆด์ˆ˜ ์žˆ๋‹ค!

 

action(): ๋ฐ์ดํ„ฐ ๋ณด๋‚ด๊ธฐ

 

ํ•ด๋‹น ๋ผ์šฐํ„ฐ์—์„œ form์ด ์ „์†ก๋ ๋•Œ ์‹คํ–‰๋œ๋‹ค.

 

โ—๏ธ react-router-dom์˜ Form ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด , form ์ „์†ก์„ ์ฒ˜๋ฆฌํ•ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์š”์ฒญ์„ ์ „์†กํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰์•„์ฃผ๊ณ , ๋ชจ๋“  ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•ด ํ•ด๋‹น ๋ฐ์ดํ„ฐ์˜ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•ด์ค€๋‹ค.

 

form์•ˆ์˜ name ์†์„ฑ์— ์ •์˜ํ•œ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•œ๋‹ค.

import NewPost,{action as newPostAction} from './routes/NewPost'

const router=createBrowerRouter([
  {path:'/', 
  element:<RootLayout/>, 
  children:[
    {path:'/',
    element:<Posts/>,
    loader: postsLoader
    children:[
      {path:'/create-post',element:<NewPost/>,action:newPostAction}
    ]}
  ]}
])

 

๐Ÿ‘‰๐Ÿป ๋•๋ถ„์—, useState, eventhandler ํ•จ์ˆ˜๋“ค๋„ ๋ชจ๋‘ ์‚ญ์ œํ•  ์ˆ˜์žˆ๋‹ค.

 

redirect()

action, loaderํ•จ์ˆ˜ ์•ˆ์—์„œ ํ˜ธ์ถœํ•ด, ์ด ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. (์‘๋‹ต ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์ง)

-> ์šฐ๋ฆฌ๊ฐ€ ์ด๋™ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ๋กœ๋กœ ์ด๋™์‹œ์ผœ์ค€๋‹ค.