wecode 2차 프로젝트가 시작되었다!!!!
2차 프로젝트로는 내가 의견 낸 라네즈 사이트를 클론하게 되었다!!!
(참고로 우리팀 이름은 마요네즈........ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ)
내가 맡은 기능은 로그인(소셜 로그인 기능), 회원가입, 브랜드 소개 페이지, 장바구니, 리뷰 게시판이당!
여기까지 빨리 끝낼 수 있다면 다음 2순위 (매장 찾기, 예약 페이지 등...) 중에 골라서 해보기로!!
그리고 이번 2차 프로젝트 부터는 기존대로 class형 component과 scss 파일을 사용해도 되고, function형 component(feat.Hooks), styled component 를 공부해서 사용해도 되는데, 나는 뭐 당연히 후자 도전~!!!
이 자는 몸의 70%가 도전으로 이루어져 있다.
이름에서부터 알 수 있듯이, 함수형 컴포넌트란 함수를 기반으로 작성하는 컴포넌트를 말한다.
기존에 우리가 사용했던 클래스형 컴포넌트에 비해 훨씬 짧고 직관적인 코드를 짤 수 있고, 함수형 프로그래밍을 할 수 있게 해준다.
아래에서 나오는 Hooks가 도입되면서 함수형 컴포넌트에서도 클래스형 컴포넌트의 라이프 사이클 메서드와 같은 기능을 사용할 수 있게 되었다.
react 공식 문서에서도 함수형 컴포넌트 + Hooks 조합을 추천하고 있으며, 아직 낯설고 어려운 개념이긴 하지만 2차 프로젝트는 함수형 컴포넌트 + Hooks + styled component로 진행해보려고 한다!
리액트 v16.8 로 업데이트되면서 추가된 기능으로서,
함수형 컴포넌트에서도 상태 관리를 할 수 있는 useState, 렌더링 직후 작업을 설정하는 useEffect 등의 기능 등을 제공한다. (기존의 함수형 컴포넌트에서 할 수 없었던 작업....!)
함수형 컴포넌트에서도 가변적인 상태를 지니고 있을 수 있게 해준다.
함수형 컴포넌트 안에서 상태를 관리해야 하는 일이 생기면 이 Hooks를 이용하면 된다.
js
파일 내에서
import React, { useState } from 'react'; // import 로 useState 를 불러온다!
const SayLove = () => { // 함수형 컴포넌트 시작~!
const [value, setValue] = useState(0);
const [isModalActive, setIsModalActive] = useState(false);
return (
<div>
<p>
<b>{value}</b> 만큼 사랑합니다...
</p>
<button onClick={() => setValue(value + 1)}>+1</button>
<button onClick={() => setValue(value - 1)}>-1</button>
<button onClick={() => setIsModalActive(!isModalActive)}>
modal btn
</button>
</div>
);
};
export default SayLove;
배열 비구조화 할당의 쉬운 예시!
const array = [1, 2];
const [one, two] = array;
console.log(one, two); // 1, 2
const [value, setValue] = useState(0);
예시에서 앞의 이 코드는 배열 비구조화 할당이다! (객체 비구조화 할당이랑 비슷함!)
useState(0)
도 결국은 함수이다! 뒤에 (0)
은 파라미터인데, 상태의 기본값
위의 예시에서는 SayLove
컴포넌트의 기본 상태값을 0으로 설정해준것!
이 useState(0)
함수는 실행후에 배열을 반환하는데, 이 배열의 첫번째값 value
와, 두번째값 setValue
을 배열 비구조화 할당을 이용해서 따로 선언해준다.
이때 [value, setValue]
는
value
: 원소의 현재 상태 값setValue
: 상태를 설정하는 Setter
함수 이다.const [value, setValue] = useState(0); // 는
const numberState = useState(0);
const number = numberState[0];
const setNumber = numberState[1]; // 이 3줄과 같다!
즉, useState(0)
함수에 파라미터를 넣어서 호출하면 전달받은 파라미터로 값이 바뀌게 되고, 컴포넌트는 정상적으로 리렌더링 된다.
만약 컴포넌트에서 관리해야 할 상태가 여러 개라면 어떻게 해야 할까??
그냥 useState
를 여러번 쓰는 방법이 있고, 하나의 useState
를 설정한 뒤, 여러개의 상태값을 관리하는 방법이 있다!
useState
를 여러번 쓰는 방법은, js
파일 내에서
const Info = () => {
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
const onChangeName = e => {
setName(e.target.value);
};
const onChangeNickname = e => {
setNickname(e.target.value);
};
return (
<div>
<div>
<input value={name} onChange={onChangeName} />
<input value={nickname} onChange={onChangeNickname} />
</div>
<div>
<div>
<b>이름:</b> {name}
</div>
<div>
<b>닉네임: </b>
{nickname}
</div>
</div>
</div>
);
};
이렇게 정말 여러개 써주는거고!
useState
하나에 여러 상태를 관리하는 방법은, js
파일 내에서
import React, { useState } from 'react';
const Info = () => {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = (e) => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 전개 구문으로 펼쳐서 /복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정 (이때 [name]은 계산된 속성명 구문 사용)
});
};
const onReset = () => {
setInputs({
name: '',
nickname: '',
})
};
return (
<div>
<input name="name" placeholder="이름" onChange={onChange} value={name} />
<input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
이렇게 useState
의 파라미터로 객체를 전달한다.
이때 주의할 점은, 리액트의 state에서 객체를 수정해야 할 때에는
inputs[name] = value;
이렇게 직접 수정하면 안되고,
setInputs({
...inputs,
[name]: value
});
이렇게 새로운 객체를 만들어서 새로운 객체에 변화를 주는 식으로 사용해야 한다.
왜?
아직은 어려운 개념이긴 한데.... react 의 불변성을 지키기 위해서! 라고 한다.
불변성을 지켜야지만, 리액트 컴포넌트에서 상태가 업데이트가 됐음을 감지 할 수 있고 이에 따라 필요한 리렌더링이 진행된다.
inputs[name] = value
이렇게 기존 상태에 직접 접근해서 수정하면, 값이 바뀌어도 리렌더링 되지 않는다.
또한, 불변성을 지켜야지만 컴포넌트의 업데이트 성능 최적화를 제대로 할 수 있다.
useEffect 는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 기능이다.
쉽게 말하면, 클래스형 컴포넌트의 componentDidMount
+ componentDidUpdate
를 합친 형태라고 이해하면 된다!
import React, { useState, useEffect } from 'react';
const Info = () => {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
useEffect(() => { // useEffect 적용!
console.log('렌더링이 완료되었습니다!');
console.log({
name,
nickname
});
});
const { name, nickname } = inputs;
const onChange = (e) => {
const { value, name } = e.target;
setInputs({
...inputs,
[name]: value
});
};
const onReset = () => {
setInputs({
name: '',
nickname: '',
})
};
return (
<div>
<input name="name" placeholder="이름" onChange={onChange} value={name} />
<input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default Info;
useEffect
에서 설정한 함수를 componentDidMount
처럼 사용하고 싶을때!
즉, 컴포넌트가 화면에 가장 처음 렌더링 될 때만 실행되야 할 경우, (업데이트 때는 실행 할 필요가 없는 경우) 에는 함수의 두번째 파라미터로 비어있는 배열을 넣으면 된다.
위의 예시에서,
useEffect(() => {
console.log('렌더링이 완료되었습니다!');
console.log({
name,
nickname
});
});
를
// useEffect 안에 콜백 함수를 넣어준다!
useEffect(() => {
console.log('마운트 될 때만 실행됩니다.');
}, []); // [] 의 값이 바뀔때마다 계속 실행, 근데 빈배열은 즉 처음 한번만 실행된다!
이렇게 바꿔주면 끝!
💁🏻♀️ 꼭
[]
을 넣어야만 하는건 아니다!
두번째 파라미터의 값이 변경될 때 첫번째 파라미터가 실행되는것이므로,
두번째 파라미터에 불변값을 넣어주면 되는데, 실제로 위 코드를useEffect(() => { console.log('마운트 될 때만 실행됩니다.'); }, "hello");
이렇게 작성하거나,
"hello"
자리에 숫자등의 기본형 데이터 타입을 넣어도 잘 동작한다!
하지만,[]
빈 배열을 작성하는것이 컨벤션이므로 왠만하면 뻘짓하지 말고[]
쓰자🤣!!
useEffect를 이용해서 data를 받아오기!
useEffect( () => {
fetchInitialData(); // useEffect 안에서 바로 fetch를 사용하지 말고, fetch 역할의 함수를 실행할것!
} )
const fetchInitialData = async () => {
const res = fetch('URL주소');
const initialData = await res.json();
setDatas(initialData);
}
setDatas(initialData)
를 통해 datas
상태에 초기값으로, fetch를 통해 받아온 데이터를 설정한다.
근데 이렇게만 하면, 렌더링이 계속계속계속 무한으로 반복된다!
왜? useEffect
는 렌더링 된 직후에 실행되는데, 이 때 data를 fetch로 받아와서 초기 state를 setDatas
해주었고, setState가 일어나면 다시 렌더링 되기 때문에, 렌더링 직후에 실행되는 useEffect
가 또 실행되는것!
그러니까 위의 예시처럼, 두번째 인자에 빈배열을 추가해준다!
useEffect( () => {
fetchInitialData();
}, [] )
실제 데이터가 받아와지는 동안 딜레이가 생기는 경우가 많다.
이때, loading
값을 관리하여 예쁜 로딩바나 로딩 애니메이션으로 사용자 경험을 높일 수 있다.
const [loading, setLoading] = useState(false);
loading state를 추가해주고,
const fetchInitialData = async () => {
setLoading(true); // data를 받아오기 시작할 때 loading 값을 true로!
const res = fetch('URL주소');
const initialData = await res.json();
setDatas(initialData);
setLoading(false); // data를 받아오는게 끝날 때 loading 값을 false로!
}
data를 받아오는 fetchInitialData
메서드에 다음과 같이 setLoading
을 실행한다.
그리고 로딩창을 보여줄 component의 return 위에
let toDoList = 로딩 화면
if (!loading) toDoList = 로딩이 끝나면 보여줄 내용
이라고 작성해준다!
useEffect
에서 설정한 함수를 componentDidUpdate
처럼 사용하고 싶을때!
즉, 컴포넌트의 특정 값이 변경될 때만 useEffect
를 호출하고 싶을 때에는 함수의 두번째 파라미터로 전달되는 배열 안에 검사하고 싶은 값을 넣으면 된다.
위의 예시에서,
useEffect(() => {
console.log('렌더링이 완료되었습니다!');
console.log({
name,
nickname
});
});
를
useEffect(() => {
console.log(name);
}, [name]); // [name] : [name] 값이 바뀔 때만 실행, 즉 처음 한번만 실행된다!
이렇게 바꿔주면 끝!
참고로, [name]
이라는 배열 안에는 useState
를 통해 관리하고 있는 상태를 넣어줘도 되고, props 로 전달받은 값을 넣어줘도 된다.
참고로 위의 코드를 클래스형 컴포넌트에서 쓴다면 이렇게 쓸 수 있다.
componentDidUpdate(prevProps, prevState) {
if (prevProps.value !== this.props.value) {
doSomething();
}
}
handleBtnColor = () => {
this.setState({
color: "red"
}, () => console.log(this.state.color))
}
class형 component에서는 이렇게 작성했다!
( state의 color 값이 바뀔때마다 console.log
함수를 실행!)
const [color, setColor] = useState("blue")
const handleBtnColor = () => {
setColor("red")
}
useEffect(() => {
console.log(color)
}, [color])
function형 component에서는 이렇게 작성할 수 있다!!
개발 왕초보 코린이입니다!
이 내용은 각종 강의&구글링을 통해 배운 내용을 정리하는 것으로, 제가 이해하고 넘어간 개념이 틀렸거나 더 보충할 개념이 있다면 댓글 남겨주시면 정말 감사하겠습니다!!
In today's competitive job market, obtaining Salesforce certification can significantly boost your career prospects. Among the most sought-after certifications is the Salesforce Certified Platform Developer I (CRT-450) credential. This certification validates your skills and expertise in developing custom applications on the Salesforce platform, making you a valuable asset to any organization leveraging Salesforce's powerful CRM capabilities.
CRT-450 exam dumps
이번에 React에 대해서 공부하는 중인데, 제가 필요한 부분을 잘 설명해주셔서 좋은 것 같습니다.
감사합니다!