내배캠 TIL 2022.12.08
오늘 한 일
09:30am ~ 11:00am : 국취제 자소서, 면접 특강
11:00am ~ 11:30am : 국취제 상담 갔다옴
11:30am ~ 12:30pm : 치킨먹음
12:30pm ~ 12:50pm : vscode 기본 터미널 git bash로 바꿔줌
늦잠 금지....!
yarn 관련된 명령어가 powershell 터미널에서는 전혀 실행이 안 되어서 vscode 기본 터미널을 git bash로 바꾸어주었다.
https://amaranth1ne.tistory.com/50
styled-component 이용해보기
yarn add styled-component 명령창에 입력
vscode-styled-components 플러그인 다운로드
(손에 매니큐어 칠하는 이미지)
import styled from "styled-components"; // 스타일 컴포넌츠를 임포트한다
import "./App.css";
const StBox = styled.div` //백틱 안에 넣어준다. div 말고 다른 태그들도 된다.
width: 100px;
height: 100px;
border: 1px solid red;
margin: 20px;
`;
function App() {
return <StBox>박스</StBox>;
}
export default App;
색 정보를 props로 넘겨줄 수 있다. 부모가 자식 컴포넌트에 보낼 때 처럼
템플릿 리터럴이라서 백틱을 쓰고 달러표시가 있다.
화살표에 빨간색이 생기는데 그래도 작동은 한다.
const StBox = styled.div`
width: 100px;
height: 100px;
border: 1px solid ${(props) => props.borderColor};
margin: 20px;
`;
function App() {
return (
<div>
<StBox borderColor="red">빨간 박스</StBox>;
<StBox borderColor="green">초록 박스</StBox>;
<StBox borderColor="blue"> 파랑 박스</StBox>;
</div>
);
}
getBoxName이라는 함수를 만들고
map으로 돌려준다.
const boxList = ["red", "green", "blue"];
// 색을 넣으면, 이름을 반환해주는 함수를 만듭니다.
const getBoxName = (color) => {
switch (color) {
case "red":
return "빨간 박스";
case "green":
return "초록 박스";
case "blue":
return "파란 박스";
default:
return "검정 박스";
}
};
function App() {
return (
<div>
{boxList.map((box) => (
<StBox borderColor={box}>{getBoxName({ box })}</StBox>
))}
</div>
);
}
React Hook - useState
기본 형식
const [state, setState] = useState(initialState);
원래는 useState라는 함수가 배열을 반환하고 이것을 구조 분해 문법으로 꺼내놓은 것이다. (이해 안됌)
State가 원시데이터 타임이 아닌 객체 데이터 타입인 경우에 불변성을 유지해줘야한다.
함수형 업데이트
//기존에 우리가 쓰던 방식
setState(number + 1)
//함수형 업데이트
setState(() => { })
- 기존 setNumber 쓴 경우
const App = () => {
const [number, setNumber] = useState(0);
return (
<div>
{/* 버튼을 누르면 1씩 플러스된다. */}
<div>{number}</div>
<button
onClick={() => {
setNumber(number + 1); // 첫번째 줄
setNumber(number + 1); // 두번쨰 줄
setNumber(number + 1); // 세번째 줄
//batch된다. React에서 명령을 하나로 모아서 한번만 명령을 내린다.
}}
>
버튼
</button>
</div>
);
}
- 함수형 setNumber 쓴 경우
const App = () => {
const [number, setNumber] = useState(0);
return (
<div>
{/* 버튼을 누르면 3씩 플러스 된다. */}
<div>{number}</div>
<button
onClick={() => {
setNumber((previousState) => previousState + 1);
setNumber((previousState) => previousState + 1);
setNumber((previousState) => previousState + 1);
//명령을 모아서 순차적으로 각각 한 번씩 실행시킨다.
}}
>
버튼
</button>
</div>
);
};
React Hook - useEffect
- useEffect가 속한 컴포넌트가 화면에 렌더링 되거나 사라졌을 때 useEffect가 실행된다.
- (컴포넌트가 mount 되거나 unmount 되었을 때 실행)
- console에 두번씩 찍히는 이유는 strictmode 가 적용되어 있기 때문이다
- 무한 실행되는 useEffect
- 예시 코드스니펫을 복붙하면 input에 한글자 넣을 때 마다. useEffect가 무한 실행되는 것을 볼 수있다.
- State가 변경되어서 리렌더링이 일어났고 리렌더링이 일어나서 useEffect가 실행된 것이다.
- 해결 방법은 의존성 배열
- useEffect를 제어할 수 있는 방법에는 의존성 배열이 있다.
- 배열 안의 값이 바뀔 때에만 useEffect를 실행해라는 설정
- 빈 배열을 넣은 경우
- 배열 안에 바뀔 값 자체가 없다 = 어떤 값이 변하더라도 useEffect는 실행이 안된다.
- 이걸 넣으니까 처음 렌더링 할 때만 useEffect가 실행되고 그 이후 state가 변경되더라도 useEffect 실행되지 않는다
useEffect(() => {
console.log("hello useEffect");
}, []); //마지막에 들어간 대괄호가 의존성 배열이다.
- 배열에 값을 넣어준 경우
useEffect(() => {
console.log("hello useEffect");
}, [value]);// 의존성 배열 안의 밸류 값이 변할 때마다 useEffect 실행
cleanUp을 이용해 useEffect를 활용하는 방법
-아직 안 배워서 간단하게만 설명하고 지나감
- 사용방법
useEffect(() => {
//화면에 컴포넌트가 나타났을(mount) 때 실행하고자 하는 함수를 넣어주세요
return () => {
//화면에서 컴포넌트가 사라졌을 (unmount) 때 실행하고자 하는 함수를 넣어주세요.
}
}, []);
예를 들어 버튼을 클릭해서 다른 링크로 넘어가서 현재 화면 컴포넌트가 사라졌을 때
return 이후의 내용이 실행된다.
strict mode와 life cycle에 대해서 알아보자
strict mode는 모던 자바스크립트 튜토리얼 페이지에서 읽었고
lift cycle은 입문 주차에 검색해봤는데 둘 다 기억이 가물가물
엄격모드에 대하여
https://ko.javascript.info/strict-mode
lifecycle에 대한 정리글
리액트 라이프사이클의 이해
시작하기 전에 리액트 라이프 사이클을 원래 알고는 있었지만 정확하게 한번도 정리해본 적이 없는 것 같아서 글을 쓰게 되었다. 더불어 리액트 라이프 사이클과 최근 사용되는 Hooks와도 비교해
kyun2da.dev
이 글을 봤을 때 mount와 unmount는 라이프 사이클의 마지막 단계이고, Dom을 이용하여 보여주고 없애는 것 같다.
Redux 기본 설정
redux 패키지랑, 리액트랑 리덕스를 연결해주는 패키지를 함께 다운 받았다
yarn add redux react-redux
- src 폴더 안에 redux 폴더 생성
- redux 폴더 안에 config, modules 폴더 생성
- config폴더 안에 configStore.js(파일 생성
- config 폴더 : redux의 설정과 관련된 파일 있는 곳
- configStore.js : 중앙 statestore를 만들어주는 코드가 있는 곳
- module 폴더 : 기능마다 필요한 State들을 그룹 모아 놓는 곳
- ex) todolist를 만드는 state 파일 todo.js 가 module 폴더 안에 있을 수 있다.
redux의 구성
redux는 reducer를 포함한 store다
1. action을 일으킨다(dispatch)
2. reducer가 자동 실행된다
3. reducer가 action에 맞게 store 의 데이터를 수정해준다.
1. configStore.js의 중앙 statestore를 만들어주는 코드 넣는다.
2. index.js에 redux 관련한 import 해준다
3. 원하는 module counter.js 생성한다.
4. module을 configstore.js에 import하고 reducer에 counter 넣어주어 store과 연결한다.
5. App.js에서 연결 잘 되었는지 useSelector로 store 조회해 state 값 가져와 본다.
- configStore.js의 중앙 statestore를 만들어주는 코드
import { createStore } from "redux";
import { combineReducers } from "redux";
/*
1. createStore()
리덕스의 가장 핵심이 되는 스토어를 만드는 메소드(함수) 입니다.
리덕스는 단일 스토어로 모든 상태 트리를 관리한다고 설명해 드렸죠?
리덕스를 사용할 시 creatorStore를 호출할 일은 한 번밖에 없을 거예요.
*/
/*
2. combineReducers()
리덕스는 action —> dispatch —> reducer 순으로 동작한다고 말씀드렸죠?
이때 애플리케이션이 복잡해지게 되면 reducer 부분을 여러 개로 나눠야 하는 경우가 발생합니다.
combineReducers은 여러 개의 독립적인 reducer의 반환 값을 하나의 상태 객체로 만들어줍니다.
*/
const rootReducer = combineReducers({});
const store = createStore(rootReducer);
export default store;
강사님은 폴더 파일 아이콘이 기능을 설명해주게 되어 있어서 검색해서 찾아봤다.
- index.js 기본 코드
// 원래부터 있던 코드
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
// 우리가 추가할 코드
import store from "./redux/config/configStore";
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
//App을 Provider로 감싸주고, configStore에서 export default 한 store를 넣어줍니다.
<Provider store={store}>
<App />
</Provider>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
- counter.js 코드
counter를 만들어야하는데 counter.js를 modules 폴더에 넣었다.
useState랑 달리 초기값을 객체 형태로 넣어놓았는데,
객체, 배열, 원시 데이터 다 가능하다.
객체에 여러 변수를 넣을 수 있다.
const initialState = {
number: 0,
};
// 리듀서 //변화를 일으키는 함수 //setState와 같은 역할한다
const counter = (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
- 이제 store 랑 연결하자
- configStore.js
import { createStore } from "redux";
import { combineReducers } from "redux";
import counter from "../modules/couter"; //counter import 했다.
const rootReducer = combineReducers({
counter:counter, //counter 리듀서를 넣어주었다.
});
const store = createStore(rootReducer);
export default store;
막간 화살표 함수 복습
아래 두 코드는 같은 것
const counterStore = useSelector((state) => state); //화살표 함수
const counterStore = useSelector(function (state) {
return state
});
- 연결이 잘 되었는지 확인하자
- App.js
- component에서 store를 조회할 때는 useSelector를 사용해야한다. (react-redux에서 import 해온다)
import React from "react";
import { useSelector } from "react-redux"; // import 해주세요.
const App = () => {
const counterStore = useSelector((state) => state);
//현재 프로젝트에 존재하는 모든 redux module의 state를 가져와라
const number = useSelector((state) => state.counter.number);
//counter라는 module의 number만 가져와라
console.log(counterStore);
return <div></div>;
};
export default App;
값을 변경하는 법 (counter.js 모듈에 있는 state 값 변경)
1. 컴포넌트에서 명령을 생성한다 ( App.js)
- 명령을 action 이라고 한다.
- action은 객체다.
- 반드시 type을 키 값으로 가져야한다
- value는 대문자로 작성한다 (상수라서)
- ex) {type: "PLUS_ONE"}
2. 명령(액션 객체) 보내려면 useDispatch라는 전달자 함수 Hook을 이용해야한다.
(react-redux에서 import 해온다) ( App.js)
3. 리듀서에서 액션객체 받는다 (configStore.js)
4. 변화를 만들어내는 함수인 리듀서에서 액션 객체의 조건이 일치하면 state 값 변경하는 코드 구현한다 (configStore.js)
6. useSelector로 변경된 State 값 확인한다. ( App.js)
- App.js
import React from "react";
import { useSelector, useDispatch } from "react-redux"; // 사용할 Hook들 import 해주세요.
const App = () => {
const number = useSelector((state) => state.counter.number);
//useSelector로 state 값 가져오기
const dispatch = useDispatch();
// useDispatch를 상수에 지정한다
// 이거 없애고 바로 함수 이용하니까 오류가 난다.
return (
<div>
{number}
<button
onClick={() => {
dispatch({ type: "PlUS_ONE" }); //형식에 맞는 액션 객체를 보내준다
}}
>
+1
</button>
<button
onClick={() => {
dispatch({ type: "MINUS_ONE" });
}}
>
-1
</button>
</div>
);
};
- configStore.js
// 초기 상태값
const initialState = {
number: 0,
};
// 리듀서 //변화를 일으키는 함수 //setState와 같은 역할한다
const counter = (state = initialState, action) => {
switch (action.type) {
case "PlUS_ONE":
return {
number: state.number + 1,
};
case "MINUS_ONE":
return {
number: state.number - 1,
};
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
action creator
사용방법
함수와 action value 상수를 이용하여
- counter.js
- 상수와 action creator를 module에서 만든다
- 리듀서에서의 이름도 문자열이 아닌 상수로 바꾼다
//액션 value를 상수들로 만든다
const PlUS_ONE = "PlUS_ONE";
const MINUS_ONE = "MINUS_ONE";
//Action Creator 만들어 준다. 함수다
export const plusOne = () => {
return {
type: PlUS_ONE,
};
};
export const minusOne = () => {
return {
type: MINUS_ONE,
};
};
// 초기 상태값
const initialState = {
number: 0,
};
// 리듀서 //변화를 일으키는 함수 //setState와 같은 역할한다
const counter = (state = initialState, action) => {
switch (action.type) {
case PlUS_ONE: // case에서도 문자열이 아닌 위에서 선언한 함수를 넣어준다.
return {
number: state.number + 1,
};
case MINUS_ONE:// case에서도 문자열이 아닌 위에서 선언한 함수를 넣어준다.
return {
number: state.number - 1,
};
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
- App.js
- action creator import 한다
- dispatch() 안에 있던 액션 객체 지우고 action creator 넣는다.
// src/App.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
//사용할 action creator를 import 한다.
import { plusOne, minusOne } from "./redux/modules/counter";
const App = () => {
const number = useSelector((state) => state.counter.number);
const dispatch = useDispatch();
return (
<div>
{number}
<button
onClick={() => {
dispatch(plusOne()); //액션객체를 Action Creator로 변경
}}
>
+1
</button>
<button
onClick={() => {
dispatch(minusOne()); //액션객체를 Action Creator로 변경
}}
>
-1
</button>
</div>
);
};
export default App;
왜 쓰는지? (그냥 기본 방식보다 손이 더 많이 가는 것 같은데 길게 보면 더 좋다)
1. 휴먼에러 방지하려고
액션 객체 이름을 상수로 지정해두면 자동 완성 보조기능을 지원받을 수가 있어 오타를 줄일 수 있다.
2. 유지보수 효율성이 증가한다
아주 많은 곳에 쓰인 action creator 를 수정하려면 action creator 안의 상수의 값을 한 번만 수정하면 된다.
3. 코드 가독성이 증가한다
module 안에 action creator가 정리되어 있기 때문에 module이 어떤 action을 가지는지 쉽게 확인할 수 있다.
리덕스 공식문서에 있는 action creator에 대한 글을 읽어보라고 해서 읽었는데 뭐라는지 모르겠다.
payload
액션 객체에 더 많은 키와 값을 넣어서 보내는 것을 payload라고 한다.
type 속성명을 고정이지만 나머지 속성명은 우리가 원하는대로 정할 수 있다. 하지만 커뮤에서 payload로 담아주는게 잘 되더라 해서 우리도 payload라고 속성명을 사용할거다.
N이 들어가는 것 같이 복잡한 액션 명령을 만들어서 reducer에 보내줄 때 N도 같이 담아 보내주는 것을 payload라고 한다.
payload를 이용한 코드
counter.js
const PLUS_PL = "PLUS_PL";
const MINUS_PL = "MINUS_PL";
export const plusPL = (payload) => {
//매개변수로 payload를 넣는다
return {
type: PLUS_PL,
payload, //키와 밸류가 같으면 하나만 써줄 수 있다.
};
};
export const minusPL = (payload) => {
//매개변수로 payload를 넣는다
return {
type: MINUS_PL,
payload, //키와 밸류가 같으면 하나만 써줄 수 있다.
};
};
const initialState = {
number: 0,
};
const counter = (state = initialState, action) => {
switch (action.type) {
case PLUS_PL:
// 받아온 payload를 더해준다
return { number: state.number + action.payload };
case MINUS_PL:
//받아온 payload를 빼준다
return { number: state.number - action.payload };
default:
return state;
}
};
export default counter;
App.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { plusPL, minusPL } from "./redux/modules/counter";
import { useState } from "react";
const App = () => {
const totalNumber = useSelector((state) => state.counter.number);
const [number, setNumber] = useState(0);
const dispatch = useDispatch();
//익명함수로 바로 넣어줄 수도 있지만 함수를 만들어서 onChange에 넣어주었다.
const onChangeHandler = (event) => {
//event.target이라는 객체를 value라는 키값으로 구조분해 할당한 것
const { value } = event.target;
// 자동으로 문자열로 설정되어 있는 event target value를 숫자롤 +를 붙여 바꿔준다
setNumber(+value);
};
//익명 함수로 바로 넣어줄 수도 있지만 함수를 만들어서 onclick에 넣어주었다.
const onClickAddNumberHandler = () => {
//payload로 들어갈 값을 인자로 넣어준다
dispatch(plusPL(number));
};
const onClickUnAddNumberHandler = () => {
dispatch(minusPL(number));
};
return (
<div>
<p>현재총합 {totalNumber}</p>
<p>{number}</p>
<input onChange={onChangeHandler} type="number" />
<button onClick={onClickAddNumberHandler}> + </button>
<button onClick={onClickUnAddNumberHandler}> - </button>
</div>
);
};
export default App;