useReducer 복습

  • Redux에서 차용한 것
  • state를 하나로 묶어주는 역할 state를 바꿀 때는 action을 dispatch해서 reducer에서 바꾼다.
  • Redux와의 차이점 : Redux는 state를 동기적으로 바꾸는데 반해, reducer는 비동기적으로 바꾼다.

Context API

  • props를 넘겨줄 때 부모와 자식 관계가 깊어질 수록 전달하는 것이 힘들어짐.
  • 그것을 해결하기 위한 API

state를 바꾸고자 할 때 props로 받은 dipatch로 부모 컴포넌트에 액션을 보내는 방식 대신 Context API로 바로 보내는 방식을 사용할 것.

 

MineSearch.jsx

import React from 'react';
import MineTable from "./MineTable";
import {useReducer} from "react/index";
import Form from "./Form";

const initalState = {
    tableData: [],
    timer: 0,
    result: '',
}

const reducer = (state, action)=>{
    switch (action.type){
        default:
            return state;
    }
}
const MineSearch = () => {
    const[state,dispatch]=useReducer(reducer(), initalState);

    return (
        <>
            <Form />
            <div>{state.timer}</div>
            <MineTable />
            <div>{state.result}</div>
        </>
    );
};

export default MineSearch;

 

Form.jsx

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

const Form = () => {
    const [cell,setCell]=useState(10);
    const [row,setRow]=useState(10);
    const [mine,setMine]=useState(20);

    const onChangeRow = useCallback(e=>{
        setRow(e.target.value);
    },[]);

    const onChangeCell = useCallback(e=>{
        setCell(e.target.value);
    },[]);

    const onChangeMine = useCallback((param) => (e)=>{
        console.log(param);
        setMine(e.target.value);
    },[]);

    const onClickButton = useCallback(()=>{

    },[]);

    return (
        <div>
            <input type="number" placeholder="세로" value={row} onChange={onChangeRow}/>
            <input type="number" placeholder="가로" value={cell} onChange={onChangeCell}/>
            <input type="number" placeholder="지뢰" value={mine} onChange={onChangeMine(1)}/>
            <button onClick={onClickButton}>시작</button>
        </div>
    );
};

export default Form;

 

MineTable.jsx

import React from 'react';

const MineTable = () => {
    return (
        <table>
            
        </table>
    );
};

export default MineTable;

 

MineTr.jsx

import React from 'react';

const MineTr = () => {
    return (
        <div>
            
        </div>
    );
};

export default MineTr;

 

MineTd.jsx

import React from 'react';

const MineTd = () => {
    return (
        <div>
            
        </div>
    );
};

export default MineTd;

1. Docker hub 저장소 만들기

docker hub 회원이 없다면 회원가입 먼저 진행!

docker hub에 접속하고 나서 repository를 만들어주자.

저장소명 : vim-ubuntu

 

2.Docker Hub Login

실습하는 docker command창에서 도커허브 로그인을 해야 도커허브에 push할 때 엑세스 거부 에러가 뜨지 않는다.

"denied: requested access to the resource is denied"

docker login

위의 명령어를 입력하면 ID/PW를 입력하라고 나오는데 docker hub의 ID/PW를 입력하면 된다.

 

3. 우분투 이미지 실행

우리가 만들 image의 기초가 될 우분투 이미지를 실행해보자.

docker run -dit --name=myUbuntu ubuntu 
docker attach myUbuntu

4. 우분투 컨테이너에 vim 설치하기

아무것도 하지 않은 기본적인 우분투 컨테이너에는 vi 명령어가 존재하지 않는다고 나온다.

심지어 apt-get install도 안된다. (apt update로 레포지토리 정리를 업데이트해줘야함.)

apt update
apt-get install -y vim

 

vi 에디터 설치가 완료되면 /home/ubuntu 디렉토리로 이동해서 아래와 같이 작성하자.

vi hello

wq! 로 저장하고 나오자.

5. 이미지 커밋

docker commit myUbuntu ilikecoding/vim-ubuntu:1.0
docker images

docker images를 해서 커밋한 이미지가 제대로 저장되었는지 확인한다.

6. 이미지 푸시

docker push ilikecoding/vim-ubuntu:1.0

 

6번 까지 진행이 됐다면 docker hub에 접속해서 이미지가 제대로 푸시 되었는지 확인하면 끝!

 

# 컨테이너 삭제
docker stop $(docker ps -a -q --filter name=myUbuntu)
docker rm $(docker ps -a -q --filter name=myUbuntu)

#이미지 삭제
docker images #이미지 확인
docker rmi [우리가 커밋했던 이미지 ID]
docker rmi [기초가된 ubuntu 이미지 ID]

#이미지 다운로드
docker run -dit ilikecoding/vim-ubuntu:1.0 bash

 

이미지 푸시를 위해 생성되었던 컨테이너, 이미지들을 모두 지우고 docker hub에서 다시 다운로드 받아서 확인해보면 우리가 /home/ubuntu에 만들었던 hello 파일이 그대로 있는것을 확인할 수 있다.

 

 

[TIP]

Ubuntu Container에서 Bash가 실행중인 상태인데 exit를 하면 컨테이너가 종료되어버린다. 컨테이너가 종료되지 않으려면 Ctrl + P ▶Ctrp + Q 를 하면 그대로 컨테이너가 유지되면서 터미널을 나올 수 있다.

1. useCallback 사용하기

보통 함수를 props로 넘겨줄 때 useCallback을 사용하여 넘겨준다. (굳이 props로 안넘기는 상황에서도 많이 사용하는거 같음) 

근데 useCallback 주의점은 함수 내부에서 '바뀌는' state나 props를 사용하는 로직이 있다면 의존배열에 꼭 추가시켜주어야한다.

기억력이 너무 강력해서 처음 state값 그대로 가지고 있어버리는 문제를 발생시킬 수 있다.

 

2. 어떤 값 때문에 리렌더링 되는지 찾는 방법

const Td = ({rowIndex, cellIndex, dispatch, cellData}) => {
	const ref = useRef([]);
    useEffect(()=>{
    	console.log(rowIndex === ref.current[0], cellIndex=ref.current[1], dispatch=ref.current[2],cellData=ref.current[3]);
    	ref.current = [rowIndex, cellIndex, dispatch, cellData];
    },[rowIndex, cellIndex, dispatch, cellData]);
}

console.log에서 false가 나오는 값 때문에 리렌더링이 일어나는 것이다.

 

3. React.memo 사용하기

부모가 리렌더링 될 때 자식의 불필요한 리렌더링을 막고 싶다면 React.memo를 사용하자!

(강의에서는 이것으로 해결함!! 내가 클릭한 td만 리렌더링 되도록)

 

4. useMemo로 컴포넌트 자체를 기억할 수도 있다.

최후의 수단으로 활용해보라고 하심.

내부에 들어있는 내용물이 바뀌었을 때만 새로 랜더링하고 그 외에는 랜더링하지 않는 예제.

const Tr = ({rowData, rowIndex, dispatch})=>{
	...
    return (
    	{
        	Array(rowData.length).fill().map((td,i)=>{
            	useMemo(
                	() => <Td ~ ></Td>,
                    [rowData[i]]
                )
            });
        }
    )
}

 

※ react dev tools로 highlight를 사용해 최적화해야할 것들을 고를 때 빨간색만 조심하면 된다고하심. 실제로 빨간색은 서비스할 때 성능상의 문제가 나타난다고 하셨다.

+ Recent posts