[React] 인프런강의(섹션4,5)

김수현·2022년 5월 24일
0

> 섹션4 - 1

상위 컴포넌트 => 하위 컴포넌트 데이터 전달할 때 속성값 사용하지만 하위 컴포넌트가 많을 경우 속성값을 사용하면 불편해서 "context"라는 것을 사용함

  • 사용방법
    상단에 { createContext } import
import logo from './logo.svg';
import './App.css';
import React,{createContext, useState} from 'react';

const UserContext = createContext("unknown");

export default function App(){
  const [name, setName] = useState("mike");
  return(
    <div>
      <UserContext.Provider value={name}>
        <div>상단메뉴</div>
        <Profile/>
        <div>하단메뉴</div>
        <input type="text" value={name} onChange={e=>setName(e.target.value)}/>
      </UserContext.Provider>
    </div>
  );
}

const Profile = React.memo(function (){
  return (
    <div>
      <Greeting/>
      {/* ... */}
    </div>
  );
});

function Greeting(){
  return (
    <UserContext.Consumer>
      {username => <p>{`${username}님 안녕하세요.`}</p>}
    </UserContext.Consumer>
  );
}

위의 function Greeting(){}을 useContext훅을 사용해서 다음과 같이 표현

function Greeting(){
  const username = useContext(UserContext);
  return <p>{`${username}님 안녕하세요.`}</p>
}

> 섹션4 - 2

ref속성값을 사용하면 자식요소에 접근가능
상단에 useRef import

  • inputRef.current.focus(); 자동으로 커서
import logo from './logo.svg';
import './App.css';
import React,{useRef,useEffect} from 'react';

export default function App(){
  const inputRef = useRef();
  useEffect(()=>{
    inputRef.current.focus();
  }, []);

  return(
    <div>
      <input type="text" ref={inputRef}/>
      <button>저장</button>
    </div>
  );
}
  • forwordRef함수

  • 문자를 입력할 때 , 컴포넌트가 계속 렌더링 되는데 새로운 함수가 렌더링 되면서 inital text가 계속 ref속성값으로 들어가서 키보드 값이 안먹히는 것임 => useCallback()훅의 메모자이션 기능으로 해결 가능

  • 접근하는 돔의 요소가 많을 경우

import logo from './logo.svg';
import './App.css';
import React,{useContext, crateContext, useRef,useState,useEffect} from 'react';

export default function App(){
  const boxListRef = useRef({});
  function onClick(){
    let maxRight = 0;
    let maxId = '';
    for(const box of BOX_LIST){
      const ref = boxListRef.current[box.id];
      if(ref){
        const rect = ref.getBoundingClientRect();
        if(maxRight < rect.right){
          maxRight = rect.right;
          maxId = box.id;
        }
      }
    }
   alert(`오른쪽 끝 요소는 ${maxId}입니다.`);
  }

  return(
    <div>
      <div
        style={{
          display: 'flex',
          flexWrap: 'wrap',
          width: '100vw',
          height: '100%',
        }}
      >
        {BOX_LIST.map(item => (
          <div
            key={item.id}
            ref={ref=>{boxListRef.current[item.id]=ref}}
            style={{
              flex:'0 0 auto',
              width: item.width,
              height: 100,
              backgroundColor: 'yellow',
              border: 'solid 1px red',
            }}
          >{`box_${item.id}`}</div>
        ))}
      </div>
      <button onClick={onClick}>오른쪽 끝 요소는?</button>   
    </div>
  );
}

const BOX_LIST = [
  { id: 1, width: 70 },
  { id: 2, width: 100 },
  { id: 3, width: 20 },
  { id: 4, width: 30 },
  { id: 5, width: 40 },
  { id: 6, width: 80 },
  { id: 7, width: 90 },
];

> 섹션4 - 3

  • 리액트 내장 훅

  • useRef: 이전 값을 기억하고 싶을 때

  • useMemo
    : const value = useMemo(()=>runExpensiveJob(v1,v2),[v1,v2]); 두번째 배열은 의존성 배열, 의존성 배열이 변경될때만 함수가 실행됌

  • useCallback: 불필요한 렌더링을 막아줌, 의존성 배열로 관리

  • useReducer
    : 상태값을 변경할 때 사용
    : const [state, dispatch] = useReducer(reducer,INITIAL_STATE);
    : 현재 상태값과 액션이 입력이 되고 액션을 보고 상태값을 어떻게 할지 결정함
    : dispatch()로 객체 형식으로 부르면 useReducer에서 state를 변경함

  • useImparativeHandle: ref속성값을 받아서 첫번재 매개변수로 넣음 두번째 매개변수로 함수를 입력

  • useLayoutEffect: useEffect와 비슷하나, 부수효과 함수에서 연산을 많이 하면 브라우저가 먹통이 될 수도 있으니 주의. 조건에 따라 렌더링하고 싶을 때 사용. 실제 돔에 반영된 후에 함수가 실행됌

  • useDebugValue: 커스텀 훅을 만들어 사용할 때, 리액트 개발자 도구에 좀 더 풍부한 정보를 제공해줌. 디버깅할 때 편리함. -> 리액트 개발자 도구에서 확인 가능

> 섹션5 - 1

  • 컴포넌트 파일 작성법
    함수의 PropType 속성의 타입값을 입력정보 작성가능
    명명된 매개변수 사용하는게 좋음
    MyComponent.propTypes = {};
    export default function MyComponent(prop1, prop2){}
    큰 객체를 정의할 때는 컴포넌트 외부에서 사용하는게 좋음(성능상)

  • 훅끼리 모아서 관리보다 연관된 코드끼리 모아서 관리하는 것이 편함

> 섹션5 - 2

  • prop-types 패키지로 속성값 타입 정보 입력하는 방법
    : 타입이 왜 중요할까? 정적타입언어를 사용하는 것이 좋음.

  • prop-types 패키지 사용하는 이유
    : 패키지로 사전에 타입오류를 잡을 수 있고, 타입정의 자체가 중요한 문서가 될 수 있음.

  • propTypes.number / .oneOf([]) / .func() / .instanceOf() / .string / .objectOf / .isRequired(필수로사용해야하는것)

> 섹션5 - 3

  • 조건부 렌더링
    {isLogin ? ${name}님 안녕하세요. : '권한이 없습니다.'}: 삼항연산자

변수가 number,string일 경우, 확실히 boolean타입으로 바꿔줘야함. 변수 앞에 !! 두개 붙여주면 됌.

function GreetingA({isLogin, name}){
    if(isLogin){
        return <p>{`${name}님 안녕하세요.`}</p>
    } else {
        return <p>권한이 없습니다.</p>
    }
}

function GreetingB({isLogin,name}){
    return <p>{isLogin ? `${name}님 안녕하세요.` : '권한이 없습니다.'}</p>
}

function GreetingC({isEvent, isLogin, name, cash }){
    return (
        <div>
            저희 사이트에 방문해주셔서 감사합니다.
            {isEvent && (
                <div> 
                    <p>오늘 이벤트 놓치지 마세요.</p>
                    <button onClick={onClickEvent}>이벤트 참여하기</button>
                </div>
            )}
            {!isEvent && isLogin && cash <= 10000 && (
                <div>
                    <p>{name}님 안녕하세요.</p>
                    <p>현재 보유하신 금액은 {cash}원 입니다.</p>
                </div>    
            )}
        </div>
    );
}

> 섹션5 - 4

  • 컴포넌트 코드의 재사용성과 가독성 높이기
    : 관심사별로 분리하기(리팩토링)

component폴더: 속성값이나 상태값이 없는 파일, 재사용성이 높은 파일들
container폴더: 재사용성이 없는 파일들

App.js에서는 여러페이지를 라우팅하는 걸로(컴포넌트를 부르면서)

> 섹션5 - 5

  • 의존성 배열을 관리하는 방법
    : 끝에 빈 배열을 넣고, 매개변수 넣는것도 조심

  • 의존성 배열에 필요한 매개변수를 넣지 않았을 때 발생하는 문제점
    : 오래된 변수를 사용하게 되겠음

  • 부수효과 안에 있는 함수를 밖에서 사용하고 싶을 땐?
    : 함수를 밖으로 꺼내고 의존성 배열에 함수를 입력해야 함.

> 섹션5 - 6

: 부수효과 함수내에서 함수의 실행시점을 조절할 수 있음
setInterval(), clearInterval()

  • useReducer
    : 값을 변경하는 로직을 여기에 작성

> 섹션5 - 7

  • 성능을 최적화하는 방법1(렌더링)
    *component(Data) -> 가상돔과 비교 -> 실제 돔에 반영

  • React.memo는 속성값 비교함수를 통해서 컴포넌트 렌더링 과정을 생략할 수 있음
    => App.js

import './App.css';
import React,{ useState } from 'react';
import MyComponent from './MyComponents'

export default function App(){
  const [value1, setValue1] = useState(0);
  const [value2, setValue2] = useState(0);

  return(
    <div>
      <p> 실전 리액트 </p>
      <button onClick = { () => setValue1(value1+1)}> value1 증가 </button>
      <button onClick = { () => setValue2(value2+1)}> value2 증가 </button>
      <MyComponent value1={value1} value2={value2}/>
    </div>
  );

}

=> MyComponents.js

import React,{ useState } from 'react';

function MyComponents({ value1, value2 }) {
    return (
        <div>
            <p>{`value1: ${value1}`}</p>
            <p>{`value2: ${value2}`}</p>
        </div>
    );
}

function isEqual(prevProps, nextProps) {
    return prevProps.value1 == nextProps.value1;
}

export default React.memo(MyComponents, isEqual);
  • 상태값을 불변객체로 관리하면 성능에 도움이 됌
    불변객체로 만드는것: 새로운 객체로 만든다는 뜻
    setFruits([...fruits, newFruit]);
    preProps.todos === nextProps.todos 이렇게 비교가능해짐.

> 섹션5 - 8

  • 성능을 최적화하는 방법2

> 섹션5 - 9

  • 성능을 최적화하는 방법3
import './App.css';
import React,{ useState, useEffect } from 'react';

export default function App(){
  const [flag, setFlag] = useState(true);
  useEffect(()=>{
    setTimeout(()=>setFlag(prev => !prev), 1000);
  })

  if(flag){
    return(
      <div>
        <p>사과</p>
        <p>바나나</p>
      </div>
    );
  }
  else{
    return(
      <div>
        <p>사과</p>
        <p>바나나</p>
        <p>파인애플</p>
      </div>
    );
  }

}

이렇게 하면, 어떤값이 변경됬는지 알 수 없는데, 태그에 key값을 추가하면 리액트는 같은 Key를 갖는 요소끼리만 비교를 한다.
key속성값은 id와 비슷하 느낌.

0개의 댓글