React

Suji Park·2022년 9월 30일
0
post-thumbnail

지난시간 복습

form 태그에서 name이라는 이름으로 속성의 이름을 썼던 것처럼
props도 동일하게 동작

인자 전달부분에 {}를 추가하여 인자 전달부분에서 구조 분해할당으로 props를 받아와서 사용해도된다.


중간에 중괄호를 치면 문자 뿐마닝 아니라 변수 등으로 받아올 수도 있다.

  • props 활용하기
    Props 로는 배열 같은 다양한 자료형의 전달이 가능합니다! props.arr.map
    jsx의 장점: js과 HTML을 혼용할 수 있도록 해서 편한 사용가능

  • 컴포넌트 꾸미기
    JSX문법으로 객체 자체를 인라인에 선언해서
    객체 형태에 각각의 속성을 넣는다. (camelCase로)
    React에서 제공하는 문법이다.

  • Styled Components

    컴포넌트 레벨에서 바로 스타일 지정이 가능하다. (공동작업시 바로 체크 가능)
    PascalCase로 작성
    각각의 태그를 변수에 할당하고 해당 태그의 실제적인 태그명을 styled 를 이용하여 지정합니다!

    JS로 변형시켜서 구동되는 모듈
    for문, if문도 지원한다.

  • 조건부 렌더링
    React는 컴포넌트 형식으로 구성된다.
    이전에는 JS로 할 때는 클래스에 di-none 추가로 작동했었으나,
    React는 조건식이나 특정변수를 앞에 두고 true/false일 때 보이게 안보이게 한다.

    첫번째 컴포넌트와 두번째컴포넌트로도 사용가능하다.

  • useRef
    변수 값을 설정후 이 값이 변화가 일어나도 리랜더링이 안일어나게 (DoM요소를 변화시키지 X)
    ex. input값, 포커스 이동을 시킬 때

input을 쳐도 winputValue의 current. value에 저장된다.

  • useRef Focus
    focus 움직이기 input.current.focus
    회원가입시 입력해야할 창으로 focus로 움직이는다던지에 사용

React HOOKS

React HOOKS 등장배경

  • 태초의 리액트에서는 클래스형 컴포넌트만 사용 (컴포넌트 별 상태 관리 및 라이프 사이클 기능을 지원)

  • 메모리 문제 등 함수형으로 바뀜

  • 기존 클래스형 컴포넌트에서 사용하던 편리한 기능(리액트의 핵심)을 함수형에 적용하려니 기존 것을 그대로 사용할 수는 없었고 새로운 것에 대한 필요성을 느낌
    -> 그래서 탄생한 것이 React HOOKS 입니다

  • 앞에 use 가 붙은 애들이 HOOKS 들이죠
    useState / useRef / useEffect / useContext / useMemo / useCallback / useReducer

React.Fragment

Fragment란 파편을 뜻한다.

컴포넌트를 생성해서 넣어보면, 의미없는 div가 3개가 겹치게된다.
root> app> div(컴포넌트로 사용하기 위한 부모용)> 실제 사용하는 html

리턴 값에서 최상위 태그 역할하는 div를 빼면, 에러가 뜬다.
React는 JSX Fragment를 추천.

  • 실제 리액트에서 컴포넌트를 조합할 때, 최상위에 div 를 사용하지 않고 반환해야만 하는 경우가 생기게 된다.
  • CSS 가 깨진다거나, 테이블 요소 사이에 div 요소가 들어가면 에러가 뜨기 때문이죠!
  • 그럴 때 쓰는 것이 바로 React.Fragment 입니다!
  • 이건 React 라이브러리의 기능이므로 React 라이브러리 추가 필요

React.Fragment -> <> </>

  • 개발자들은 축약의 민족이기 때문이 이렇게 긴 코드를 용납 못합니다!
  • <React.Fragment> 는 <> 로 대체가 가능합니다! :)

React. Fragment가 필요할 때

하지만 !!! 빈 태그 안에 속성값을 줘야할 때는 React.Fragment를 사용한다.
빈 태그에는 값을 못 주기 때문에 !!! (1. 배열을 만들어서 반환해야하는 키 값 또는 속성값을 전달해야하는 상황)

  • 먼저 App.js 에 가서 ReactFragment 컴포넌트와 동일한 코드를 작성

    & flex + spacebetween 적용시

  • ReactFragment 최상위 요소를 div로 변경해서 적용시

  • Div 가 생기게 되어서 이전 결과물과는 완전히 다른 결과물이 나오게 됩니다!
  • 따라서, 이런 일을 피하려면 React.Fragment <>를 써야한다.

테이블 요소에 테이블 내용을 컴포넌트로 삽입하는 경우

  • 그런데 테이블 요소 안에는 div 태그가 들어가지 못합니다!
  • 이럴때 문제가 생기는데 이것을 React.Fragment 로 해결이 가능합니다!

CSS문제가 생길 것 같다면 React.Fragment 사용
구조적으로 div가 분리가 될 경우

useState vs useRef vs Variable

State 는 변경이 되면 바로 리렌더링이 일어나기 때문에 버튼을 클릭하면 바로바로 반영이 됩니다!
Ref 는 리렌더링이 일어나지 않기 때문에 버튼을 클릭하면 Console.log 에만 찍히다가 컴포넌트가 리렌더링이 되면 그 때 한꺼번에 반영 됩니다
그런데 왜 변수는 Console.log 에는 잘 찍히다가 렌더링이 되면 0 만 나올까요?

state는 하나하나 올라가고
Ref는 값을 유지하고 있다가 렌더링 됐을 때 한번에 변화
Variable은 리렌더링 되면 초기화가 된다.

Life Cycle

컴포넌트의 Life Cycle

  • 컴포넌트는 최초에 화면에 등장 할 때 -> Mount
  • 컴포넌트의 state 변화로 리렌더링 될 때 -> Update
  • 화면에서 사라질 때 -> Unmount
  • 생명 주기를 가진다.

  • 리액트의 장점은 컴포넌트별 상태 관리 및 리렌더링에 있기 때문에 Life Cycle에 대한 기능이 많다.
  • 클래스형 컴포넌트(componentDidMount/componentDidUpdate/componentWillUnmount)에서 함수형 컴포넌트로 넘어 가면서 기존의 Life Cylce 을 담당하던 기능을 하나의 HOOK에 추가 시켰습니다!
  • 바로 UseEffect라는 하나의 Hook에 묶어버렸다.

useEffect

(1) 무조건 실행 Mount

  • 인자를 2개를 받는다.
  • 첫번째 인자는 무조건 콜백 함수로 던져야한다.
  • 함수 내부에 하고싶은 작업을 쓴다.
  • 첫번째 콜백인자만 전달하면 렌더링 될 때마다 실행된다.

(2) 변화될 때 실행 Update

  • 두번째 인자
  • array안에는 state도 되고, value도 된다.
  • value 뒤에 state, Ref, 변수를 넣게 되면 변하는 지 안변하는지 지켜보고있따가.
  • 변할 때 실행된다.

  • 둘의 공통점은 첫 렌더링될 때 실행된다는 것이다.

(3) 첫렌더링만 하고싶다면 Unmount

  • 두번째 인자를 빈 배열로 []
  • 빈 배열은 변화하지 않으니 첫 렌더링만 한다.

  • useEffect에 첫번재 인자 안에 return으로 콜백을 준다.

useEffect Dependency

  • useEffect 는 두번째 인자로 Dependency Array 를 받습니다
  • 해당 Array 에는 변수를 넣을 수가 있으며, 해당 변수가 변경 될 때에만 useEffect 내부의 함수가 실행 됩니다!
    • 빈 배열 [] 을 넣으면 최초 마운트 시에만 실행이 됩니다!

useRef

    setText(inputValue.current.value) // useRef
    // input 태그에 useRef를 저장하는 것에 쓰는건지 / 참조하는건지 잘 구분
    // 저장할 때는 useRef 선언한 것. current ( 저장소로 쓴다면 초기화를 시켜야 한다.)
    // 값을 참조할 때는 선언한 것.current.value로 한번 더 들어가야한다. 

/ useRef
// input 태그에 useRef를 저장하는 것에 쓰는건지 / 참조하는건지 잘 구분
// 저장할 때는 useRef 선언한 것. current ( 저장소로 쓴다면 초기화를 시켜야 한다.)
// 값을 참조할 때는 선언한 것.current.value로 한번 더 들어가야한다

실습: 컴포넌트 타이머

  • App.js 에는 ‘보이기’ 라는 버튼이 하나 있습니다. 해당 버튼을 클릭하면 PracticeTimer 가 마운트 됩니다.
  • 버튼을 클릭하면 PracticeTimer 컴포넌트가 마운트 되고 마운트가 된 시간을 초단위로 기록하는 타이머가 실행 됩니다.
  • PracticeTimer 에도 ‘시간’ 버튼이 존재하며, 해당 버튼을 누르면 지금까지 마운트가 된 시간을 출력해 줍니다!
  • ‘보이기’ 버튼을 한번 더 클릭하면, PracticeTimer 가 Unmount 되고 타이머도 종료 되어야 합니다!

추가, ‘보이기‘ 버튼이 클릭 되면 버튼 이름을 ‘숨기기’로 변경 하기!
추가, 페이지가 처음 시작 되면 ‘보이기‘ 버튼에 포커스가 이동하도록 처리

import { useEffect, useRef, useState } from "react";

export default function PracticeTimer() {
  const [ render, setRender ] = useState(0);
  const time = useRef(0);

  useEffect(()=> {
    const timer = setInterval(() => {
      time.current = time.current + 1; // Ref가 Interval 1초에 한번씩 값이 올라간다. 
      console.log(timer.current);
    }, 1000); // 1000ms = 1초

    return() => { // 위의 useEffect가 언마운트되면 실행되는 코드 
      clearInterval(timer);
      console.log("타이머 종료");
    }
  },[]); // 켜질 때 한번만 실행되도록 빈 배열 켜기

  const showTime = () => {
    setRender(render + 1);
  }

  return (
    //  3. 시간 버튼을 누르면 지금까지 마운트가 된 시간을 출력해 줍니다!
    <>
      <h1>{time.current}</h1> 
      <button  onClick={showTime}>시간</button>
    </>
    
  ) 
}

App.js

// import './App.css';
import { useEffect, useRef, useState } from 'react';
import PracticeTimer from './components/PracticeTimer';


function App() {
  const [show, setShow] = useState(false);
  const changeFocus = useRef(); // 돔요소를 참조할 때는 데이터를 저장하려는 것이 아니기 때문에 useRef를 선언만 하면된다.(초기값 지정필요x)

  useEffect(()=> {
    changeFocus.current.focus(); // useEffect 안에 있기 때문에 한번만 될 것이다. 
  },[]);

  return (
  // 1. 버튼을 클릭하면 PracticeTimer 컴포넌트가 마운트 되고 
    <div className='App'>
      { show && <PracticeTimer/>}
      <button ref={changeFocus} onClick={()=> setShow(!show)}>{show? "숨기기" : "보이기"}</button>
    </div>
  );
}

export default App;
profile
천방지축😛 얼레벌레🙄 빙글빙글🙃 돌아가는 수지의 코드~🎵

0개의 댓글