엘리스 48일차 수요일 실시간 강의 React.js Hook

치즈말랑이·2022년 6월 8일
0

엘리스

목록 보기
40/47
post-thumbnail

출처: 엘리스 , https://ko.reactjs.org/docs

이고잉님 강의

복습

npx create-react-app@latest .
git remote add origin 깃주소

package.json에 homepages 추가

{
  "name": "reacttest",
  "version": "0.1.0",
  "private": true,
  "homepage": "https://mcprotein.github.io/react-review/",
~

npm run build
npx gh-pages -d build

이걸 한번에 해줄 방법

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "deploy": "npm run build && npx gh-pages -d build"
  },

<Button variant="outlined" onClick={createHandler}> 여기다가 createHandler() 처럼 함수로 주면 웹열리자마자 실행됨 html의 onclick과 다름
리액트에서는 onClick에다가 무조건 함수를 준다.

동적으로 생성된 값은 key값을 부여해서 리액트가 추적하기 쉽게 한다.
클로저: 자기가 속한 함수의 지역변수에 접근할 수 있다.

mode의 값이 바뀌었을 때, App()가 다시 호출되고, 그 return 값이 웹페이지에 반영되게 하고 싶다.

배열 안에 있는 객체에 key값이 필요한 이유: https://react.vlpt.us/basic/11-render-array.html

전체코드

import "./App.css";
import { useState } from "react";
import Button from "@mui/material/Button";
import ButtonGroup from "@mui/material/ButtonGroup";

function HeaderTag(props) {
  return (
    <header>
      <h1>
        <a
          href="/"
          onClick={(evt) => {
            evt.preventDefault();
            console.log(props);
            props.onSelect();
            console.log("evt", evt);
          }}
        >
          Web
        </a>
      </h1>
    </header>
  );
}

function Nav(props) {
  const list = props.data.map((e) => {
    return (
      <li key={e.id}>
        <a
          href={"/read/" + e.id}
          onClick={(evt) => {
            evt.preventDefault();
            props.onSelect(e.id);
          }}
        >
          {e.title}
        </a>
      </li>
    );
  });

  return (
    <nav>
      <ol>{list}</ol>
    </nav>
  );
}

function Article(props) {
  return (
    <article>
      <h2>{props.title}</h2>
      {props.body}
    </article>
  );
}

function App() {
  const [mode, setMode] = useState("WELCOME");
  const [id, setId] = useState(null);
  console.log(id);
  const topics = [
    { id: 1, title: "html", body: "html is ..." },
    { id: 2, title: "css", body: "css is ..." },
  ];
  function createHandler() {
    alert("create!");
  }
  let content = null;
  if (mode === "WELCOME") {
    content = <Article title="welcome" body="Hello, WEB!"></Article>;
  } else if (mode === "READ") {
    const topic = topics.filter((e) => {
      if (e.id === id) {
        return true;
      } else {
        return false;
      }
    })[0];
    content = <Article title={topic.title} body={topic.body}></Article>;
  }
  return (
    <div>
      <HeaderTag
        onSelect={() => {
          setMode("WELCOME");
        }}
      ></HeaderTag>
      <Nav
        data={topics}
        onSelect={(id) => {
          setMode("READ");
          setId(id);
          console.log(mode);
        }}
      />
      {content}
      <ButtonGroup
        variant="contained"
        aria-label="outlined primary button group"
      >
        <Button variant="outlined" onClick={createHandler}>
          Create
        </Button>
        <Button variant="outlined" onClick={() => alert("Update!")}>
          Update
        </Button>
        <Button variant="outlined">Delete</Button>
      </ButtonGroup>
    </div>
  );
}

export default App;

function App()

function App() {
  const [mode, setMode] = useState("WELCOME"); // hook 사용
  const [id, setId] = useState(null);
  console.log(id);
  const topics = [ // topics 데이터
    { id: 1, title: "html", body: "html is ..." },
    { id: 2, title: "css", body: "css is ..." },
  ];
  function createHandler() {
    alert("create!");
  }
  let content = null; // 초기 content는 null
  if (mode === "WELCOME") {  // mode가 WELCOME일때
    content = <Article title="welcome" body="Hello, WEB!"></Article>; // Article 컴포넌트에 이렇게 넘김
  } else if (mode === "READ") { // mode가 READ일때
    const topic = topics.filter((e) => { // topics에 map을 가해서 각각의 원소 id와 id값이 같으면 true, 다르면 false 반환
      if (e.id === id) {
        return true;
      } else {
        return false;
      }
    })[0];
    content = <Article title={topic.title} body={topic.body}></Article>; // id값이 같은 원소의 title과 body만 Article 컴포넌트에 넘김
  }
  return (
    <div>
      <HeaderTag
        onSelect={() => {
          setMode("WELCOME"); // HeaderTag 누르면 Mode가 WELCOME으로 바뀜
        }}
      ></HeaderTag>
      <Nav
        data={topics}
        onSelect={(id) => {
          setMode("READ"); // Nav 누르면 Mode가 READ로 바뀌고 id값을 받아 setId를 한다.
          setId(id);
          console.log(mode);
        }}
      />
      {content} // content는 Mode가 뭐냐에 따라 다른 행동을 한다.
      <ButtonGroup
        variant="contained"
        aria-label="outlined primary button group"
      >
        <Button variant="outlined" onClick={createHandler}> // Create버튼 누르면 createHandler 함수 실행
          Create
        </Button>
        <Button variant="outlined" onClick={() => alert("Update!")}> // 이름없는 함수
          Update
        </Button>
        <Button variant="outlined">Delete</Button>
      </ButtonGroup>
    </div>
  );
}

function Article()

function Article(props) {
  return (
    <article>
      <h2>{props.title}</h2>
      {props.body}
    </article>
  );
}

function Nav()

function Nav(props) {
  const list = props.data.map((e) => {
    return (
      <li key={e.id}>
        <a
          href={"/read/" + e.id} // data={topics}로 데이터를 보내서 props.data는 topics가 된다.
          onClick={(evt) => {
            evt.preventDefault();
            props.onSelect(e.id); // 원래 onSelect는 id를 받는데, 여기는 e.id를 주고 있고, e.id가 넘어가서 
                    // onSelect={(e.id) => {
                    // setMode("READ");
                    // setId(e.id);
                    //console.log(mode); 이게 된다
        }}
          }}
        >
          {e.title}
        </a>
      </li>
    );
  });

  return (
    <nav>
      <ol>{list}</ol>
    </nav>
  );
}

Header()도 Nav()랑 같은데, Header()는 하나만 보여주고 Nav()는 topics에 있는 목록을 보여줘야해서 Header()는 id를 넘기지 않고 mode만 바꾼다.

mode는 state이므로, mode가 바뀌면 다시렌더링이 되어 App()에서 {content}가 재실행되어 목록이 바뀌게 된다.

버튼은 Material UI를 사용했다.
https://mui.com/
부트스트랩 같은데 디자인은 더 세련된거같다.


코치님 강의

onClick안에 함수 줄때 사용법

() => activeLasers()
onClick={() => activeLasers()} (O)
onClick={activeLasers} (O)
onClick={activeLasers()} (X)

State Hook

간단한 카운터 앱

import React, { useState } from 'react';

function Example() {
  // "count"라는 새 상태 변수를 선언합니다
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count => count + 1)}>
        Click me
      </button>
    </div>
  );
}

Effect Hook

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // componentDidMount, componentDidUpdate와 같은 방식으로
  useEffect(() => {
    // 브라우저 API를 이용하여 문서 타이틀을 업데이트합니다.
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

조건부 실행

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // count가 바뀔 때만 effect를 재실행합니다.

주의사항

반드시 최상위 레벨에서만 Hook을 호출해야 한다.
for문이나 if문 안에서 호출하면 안됨

모든 내용이 다들어가있는 실습문제+@ 코드

// react 라이브러리에서 useState 불러오기
import React, {useState, useEffect} from 'react'
import "../index.css"

function Counter(){
    // useState 함수 (초기값 0) 의 결과를 counter, setCounter 변수에 할당
    const [counter, setCounter] = useState(0);

    const increaseCounter = () => {
        // counter 값을 1 늘리도록 코드 작성
        setCounter(counter => counter+1);
    }
    const decreaseCounter = () => {
        // counter 값을 1 줄이도록 코드 작성
        setCounter(counter => counter -1);
    }
    
    // useEffect 함수를 사용하여 document.title 변경
    
    // 화살표 함수를 인자로 가진 useEffect 
    useEffect( () => {
        // 실행할 사이드 효과 
        document.title = `현재 카운터 숫자: ${counter}`
    }, [counter]); // counter가 변경될때만 이펙트 실행
    
    useEffect(() => {}, [counter, name]) // counter, name이 변경될때만 이펙트 실행
    useEffect(() => {}, []) // 처음 렌더링만 실행, 이후 절대 실행 x => api 최초 통신때만 데이터 받고 그후로는 데이터안받을때 사용 
    
    // 처음 렌더링때 실행x, 이후에 어떤 특정 순간에만 실행
    const [executeNow, setExecuteNow] = useState(false);
    useEffect(() => {
        if(executeNow) {
            //do whatever you want
            setExecuteNow(false);
        }
    }, [executeNow]);
    
    return(
      <div className="counter">
        <h2> 카운터 </h2>
        <div>{ counter }</div>
        <button onClick={increaseCounter}>증가하기</button>
        <button onClick={decreaseCounter}>감소하기</button>
      </div>
    );
}

export default Counter

더많은 내용들 => https://react-hooks-cheatsheet.com/usestate 참조

profile
공부일기

0개의 댓글