use... 함수
는 리액트 hook 함수
useState 함수
: state변수를 만들고싶을떄 사용(상태에 변화가있을경우)re-rendering
하고싶을때useEffect (콜백함수 , 의존성배열);
📍 첫번째
useEffect( ()=>{ });
👇
콜백함수를 받음
컴포넌트가 랜더링될때마다 호출이 된다. 무거운 작업을 가지고 있다고하면, 매우 비효율적이기 때문에 이 방식은 거의 쓰지않음.
📍 두번쨰
useEffect( ()=>{ },[]);
👇
첫번째 랜더링만 호출
📝 만일 의존성 배열이 비어있는 배열이라면
앞에있는 함수는 🌟 최초 랜더링 될때만 실행이 된다
만일
의존성 배열(Dependency array)
에 변수가 들어있다면
그변수가 변할때 마다앞에있는 함수가 실행
이 된다
👉👉useEffect
의 인자로 전달되는 함수 부분에 함수 return할수있다
이때 return 되는 함수는cleanup 함수
라고 한다
clean up-정리 예시
useEffect(() => { //구독... return()=> { //구독해지... } },[]);
cleanup 함수
는unmount 되기전
에 실행이 되는 함수를 의미한다
특정 코드
가 특정 상황
에서만 실행
이 되어야할떄,
✏️ 컴포넌트가
최초
로 그려질떄 한번만
✏️ 컴포넌트가re-rendering
될때마다 실행
✏️ 컴포넌트가사라질떄(unmount)
될떄 실행
useEffect.js
import React, { useEffect, useState } from 'react';
const UseEffectPage = () => {
const [cnt, setCnt] = useState(0);
const [msg, setMsg] = useState('기본값');
console.log('hi')// 이코드는 언제 시작될까? => 해당 컴포넌트가 렌더링이 될때마다 실행됨
useEffect(() => {
console.log('의존성 배열이 없다면?')
})
useEffect(() => {
console.log('useEffectPage가 최초 렌더링 될때만 실행됨')
}, []);// 두번째 인자로 빈배열을 넣으면 최초 렌더링 될때만 실행됨
useEffect(() => {
console.log('cnt가 변경될때만 실행됨')
return () => {
console.log('cnt가 unmount 될때 실행됨 🌟 (기존컴포넌트가 사라질때')
}
}, [cnt]);// 두번째 인자로 cnt를 넣으면 cnt가 변경될때만 실행됨
useEffect(() => {
console.log('cnt 혹은 msg가 변경될때만 실행됨')
}, [cnt, msg]);// 두번째 인자로 cnt를 넣으면 cnt가 변경될때만 실행됨
useEffect(() => {
return () => {
console.log('unmount 될때 실행됨(기존컴포넌트가 사라질때')
}
}, []);// 두번째 인자로 빈배열을 넣으면 최초 렌더링 될때만 실행됨
return (
<>
<h1>useEffectPage</h1>
<h2>{count}</h2>
<button onClick={() => setCnt(cnt - 1)}>-</button>
<button onClick={() => setCnt(cnt + 1)}>+</button>
<p>{msg}</p>
<input type="text" onChange={(e) => setMsg(e.target.value)} />
</>
)
}
export default UseEffectPage;
useEffect
에서의존성 배열
을 제공하지 않으면 해당 effect는컴포넌트
가 렌더링될 때마다 실행됩니다. 이로 인해 컴포넌트가렌더링될 때마다
해당 코드 블록이 실행되며,처음 렌더링
때부터 effect가 실행되어 콘솔에 메시지를 로깅합니다. 그 후에도 컴포넌트가재렌더링될 때마다
같은 메시지가 반복적으로 로깅되며, 이로 인해 불필요한 작업이 발생할 수 있으므로 주의가 필요합니다.
또하나의 컴포넌트를 만들어줄거야 ❗️
Child.js
const Child = (props) => {
useEffect(() => {
//최초 렌더링 될때만 실행됨
console.log('Child가 최초 렌더링 될때만 실행됨')
console.log(props.componentTitle, '번째 자식이 만들어짐')
//사라질때 실행됨 unmount 될때 실행됨(기존컴포넌트가 사라질때)
return () => {
console.log('props.componentTitle,번째 자식이 삭제')
//부모의 state변수 cnt를 0으로 변경
//setCnt
props.setCnt(0);
//부모의 state변수 msg를 'hi'로 변경
//setMsg
props.setMsg('hi');
}
}, []); // 두번째 인자로 빈배열을 넣으면 최초 렌더링 될때만 실행됨
const onRemoveClick = (number) => {
//number에는 뭐가 저장? => event객체가 저장됨
console.log(number, '번째 자식이 삭제됨')
// props.abc([1, 2])
let res = props.arr.filter((e) => e !== number)
props.abc(res);
}
// const wrapFuc = () => {
// onRemoveClick(props.componentTitle);
// }
return (
<>
<h1>{props.componentTitle}Child Component</h1>
<button onClick={() =>
onRemoveClick(props.componentTitle)
}>Delete!</button>
<button onClick={onRemoveClick}>Delete!</button>
</>
)
}
📝 useEffect component 에서 child component 로 가지고와서 사용하려고하는데 ❓props로 받아보자
useEffect.js
const useEffectPage = () => {
const [cnt, setCnt] = useState(0);
const [msg, setMsg] = useState('hi');
const [arr, setArr] = useState([1, 2, 3]);
return (
<>
{/*
<Child componentTitle={1}/>
<Child componentTitle={2}/>
<Child componentTitle={3}/>
이렇게 3개로 반복되니 배열로만들수있겠지? ( map 함수 사용가능 )
*/}
{arr.map((e, index) => {
return <Child componentTitle={e} key={index} arr={arr} setCnt={setCnt} setMsg={setMsg} abc={setArr} />
}
)} /* return하고 중괄호 생략가능 */
<h1>useEffectPage</h1>
<h2>{cnt}</h2>
<button onClick={() => setCnt(cnt - 1)}>-</button>
<button onClick={() => setCnt(cnt + 1)}>+</button>
<p>{msg}</p>
<input type="text" onChange={(e) => setMsg(e.target.value)} />
</>
)
}
export default useEffectPage;
부모에서 자식으로
값
을 전달해줘야된다. (props
를 써서 넘겨줘야지)
component에 props로arr
setCnt
setMsg
setArr
componentTitle
들을 넘겨줬기 때문에 넘겨준것들을 사용가능.
const Child = (props) => {
//props를 받아준다
useEffect(() => {
return () => {
//부모의 state변수 cnt를 0으로 변경
//setCnt
props.setCnt(0);
//부모의 state변수 msg를 'hi'로 변경
//setMsg
props.setMsg('hi');
}
}, []);
const onRemoveClick = (number) => {
console.log(number);
//이벤트정도를 객체로 넣어서 number로 받음
//props.abc([1,2]);
props.abc(res);
}
return (
<>
<h1>{props.componentTitle}Child Component</h1>
<button onClick={() =>
//onRemoveClick({이벤트정보})
//이벤트정도를 객체로 담아서 전달
onRemoveClick(props.componentTitle)
}>Delete!</button>
<button onClick={onRemoveClick}>Delete!</button>
</>
)
}
<Child arr={arr} setCnt={setCnt} setMsg={setMsg} abc={setArr} />
}
기존배열을 기반으로 새로운 배열을 만들어주는 함수
기존배열을 기반으로
걸러내어
새로운 배열을 만들어주는 함수
배열.filter( (요소, idx, arr)=>{ return true/false } )
기존 배열의 요소 갯수만큼 반복 하면서
true가 return
되는 요소만 모아서 새로운 배열을 만들어줌
arr = [10,50,61,50,71,231];
arr.filter( (e)=>{ return e > 50 } );
=> [61,71,231]
number = 1;
arr = [1,2,3]
let res = arr.filter( (e)=>{ return e !== number } );
//e가 1이 아닌것은?
=> [2,3]
🌟 fillter 사용할때 훼손하는지 안하는지
구분해야한다.
"filter 사용할 때 훼손하는지 안하는지 구분해야한다"는 배열을 다룰 때 중요한 개념 중 하나인데, 이것은 원본 배열을 변경하지 않는 것과 관련이 있다.
원본 배열을 훼손하지 않는 경우
:
배열을 필터링하거나 수정할 때, 원본 배열을 그대로 두고 새로운 배열을 생성하는 방식이다. 이렇게 하면 원본 배열은 변경되지 않는다. 이것은 보통 함수형 프로그래밍에서 추천되는 방식이다.
예를 들어:
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(evenNumbers); // [2, 4]
원본 배열을 훼손하는 경우
:
배열을 직접 수정하여 필터링 또는 변형하는 방식이다. 이 경우 원본 배열이 변경된다. 이것은 가끔 필요한 상황이지만, 주의해야 함.
예를 들어:
const numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 !== 0) {
numbers.splice(i, 1);
i--; // 배열이 하나 삭제되었으므로 인덱스를 조정
}
}
console.log(numbers); // [2, 4]
이 경우 splice 메서드
를 사용하여 배열을 직접 수정하고 있으므로 numbers 배열이 변경됨.
원본 배열을 변경하지 않는 방식이 일반적으로 더 예측 가능하며 함수형 프로그래밍의 원칙에 부합하다. 따라서 배열을 필터링
하거나 수정할 때
원본 배열을 훼손하지 않는 방식을 사용하는 것이 좋다.
예시:
const Test=()=>{
console.log('hi')
useEffect(()=>{
console.log('welcome')
});
return(
<div>
<h1>Test</h1>
</div>
)
}
<Test/>
1. Test();
// hi 출력
// <Test/> 그려짐 mount 됨
// welcome 출력
Test 가 update 됨
기존 unmount 됨
새로 <Test/> re-rendering Test();
// hi 출력
// <Test/> 그려짐 mount 됨
// welcome 출력