[React] 내가보려고 작성한 React 코드 작성 참고자료

Inung_92·2024년 3월 2일
1

React

목록 보기
15/15
post-thumbnail

⚡️ JavaScript 기초 문법

📖 구조 분해 할당

비구조화 할당이라고도 부르며, 배열이나 객체의 속성을 개별 변수로 쉽게 추출할 수 있게 해주며 코드의 가독성 향상과 변수 초기화 과정을 직관적으로 확인

문법

// 배열 선언
const numbers = [1, 2, 3];
// 구조분해 할당
const [one, two, three] = numbers;
console.log(one);
console.log(two);

예시 1 : 배열 구조분해 할당

const numbers = [1, 2, 3];
const [one, two, three] = numbers;
// 특정 요소 생략 시 빈 자리로 두고 넘기기
const [one, , three] = numbers;

console.log(one); // 1
console.log(two); // 2
console.log(three); // 3

예시 2 : 객체 구조분해 할당

const person = {
  name: 'John Doe',
  age: 30,
  address: {
    city: 'New York',
    country: 'USA'
  }
};
// 객체에서 분해하고 싶은 속성을 지정
const { name, age, address: { city, country } } = person;
// 구조분해 할당 시 새로운 이름을 지정하고 싶은 경우 ':' 사용
const { name: myName, age: myAge } = person;

console.log(name); // John Doe
console.log(age); // 30
console.log(city); // New York
console.log(country); // USA

예시 3 : 함수 매개변수 구조분해 할당

function introduce({ name, age }) {
  console.log(`My name is ${name} and I am ${age} years old.`);
}

const person = { name: 'Jane Doe', age: 28 };
// 함수 호출
introduce(person); // My name is Jane Doe and I am 28 years old.

정리

구조 분해 할당은 코드의 가독성을 올려주는 아주 유용한 방법이다. 특히, 컴포넌트의 props 또는 state를 다룰 때 유용하게 사용된다. 선택적으로 사용하고자하는 데이터의 추출이 가능하기 때문에 가장 많이 사용되는 문법 중 하나이다.

📖 스프레드 연산자

배열이나 객체의 속성을 쉽게 복사하거나 병합하는 경우 사용

문법

const array = [1, 2, 3, 4, 5];

// 스프레드 연산자
...array

예시 1 : 배열 병합

const firstArray = [1, 2, 3];
const secondArray = [4, 5, 6];

const mergedArray = [...firstArray, ...secondArray];
console.log(mergedArray); // [1, 2, 3, 4, 5, 6]

예시 2 : 배열 복사

const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];

console.log(copiedArray); // [1, 2, 3]

예시 3 : 함수 인자로 전달

function sum(a, b, c) {
  return a + b + c;
}

const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6

예시 4 : 객체 확장 및 복사

const originalObject = { a: 1, b: 2 };
const extendedObject = { ...originalObject, c: 3 };

console.log(extendedObject); // { a: 1, b: 2, c: 3 }

const copiedObject = { ...originalObject };
console.log(copiedObject); // { a: 1, b: 2 }

정리

스프레드 연산자는 다음과 같은 역할을 하며, React에서 상태를 업데이트 하거나 props에 전달 시 불변성을 유지하며 데이터를 관리할 필요가 있는 경우 효과적으로 사용 될 수 있다.

  • 코드의 가독성 향상
  • 불필요한 중복 제거
  • 데이터의 불변성 유지

📖 나머지 연산자

스프레드 연산자와 같은 '...'기호를 사용하지만 함수의 매개변수에서 사용될 때, 전달받은 인자들을 배열로 묶어주는 역할

문법 : 스프레드 연산자와 동일

예시 1 : 함수 매개변수에서의 사용

// 요소의 갯수와 상관없이 모든 인자를 배열로 처리 가능
function sum(...numbers) {
  return numbers.reduce((acc, current) => acc + current, 0);
}

console.log(sum(1, 2)); // 3
console.log(sum(1, 2, 3, 4, 5)); // 15

예시 2 : 배열의 나머지 요소 처리

const [first, second, ...others] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(others); // [3, 4, 5]

예시 3 : 객체 비구조화 할당에서의 사용

const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };
console.log(a); // 1
console.log(b); // 2
console.log(rest); // { c: 3, d: 4 }

정리

나미저 연산자는 함수 매개변ㅅ 처리, 배열 및 객체 작업에서 매우 유용하게 사용되며 특히, 가변적인 인자를 처리하거나 특정 요소를 제외한 나머지 요소를 다룰 때 코드의 유연성을 높여줄 수 있다.

📖 Async/Await

비동기 프로그래밍을 위한 문법으로 Promise를 더 쉽고 직관적으로 사용할 수 있게 해주며, 코드의 가독성과 유지보수성이 크게 향상

문법

// Promise 사용 시
function fetchData() {
  return new Promise(resolve => {
    setTimeout(() => resolve("Data loaded"), 2000);
  });
}

// async/await 사용 시
// 일반함수
async function fetchData () {
	const response = await api();
	return response.data;
}
// 화살표 함수
const fetchData = async () => {
	const response = await api();
	return response.data;
};

// 예외 처리 필요 시
const fetchData = async () => {
	try {
		const response = await api();
		return response.data;
	} catch (error) {
		throw new Error('something wrong...');
	}
};

예시

// 비동기 함수 선언
const getProductList = async () => {
	const response = await axios.get('url');
	return response.data.productList;
};

const productList = getProductList();

정리

asycn/await은 다음과 같은 장점을 가진다.

  • 비동기 코드를 동기 코드와 유사하게 작성 가능
  • 에러 핸들링 코드가 직관적
  • 코드의 중첩이 줄어들어 콜백 지옥 회피

⚡️ JavaScript 배열 문법

📖 forEach()

배열의 각 요소에 대해 주어진 함수를 수행하며, 반환 값이 없다.

문법

const array = [1, 2, 3, 4, 5];
array.forEach(item => console.log(item));

// 출력 : 1 2 3 4 5

📖 map()

배열의 각 요소에 대해 주어진 함수를 실행하고, 그 결과로 새 배열을 생성한다. 주의할 점은 map()을 실행한 배열과 반드시 동일한 길이의 배열이 생성된다.

문법

const array = [1, 2, 3, 4, 5];
const squared = array.map(item => item * item);

console.log(squared);
// 출력 : [1, 4, 9, 16, 25]

map()의 경우 사용할 때 주의해야 할 부분은 위에서도 언급했지만 함수를 호출하는 배열과 반드시 동일한 길이의 배열을 생성한다. 그렇기 때문에 특정 조건을 가진 배열의 갯수만 반환해야한다면 다음에 배울 filter()를 사용하면 된다.

📖 filter()

배열의 각 요소에 대해 주어진 함수를 실행하고, 그 함수의 조건이 참일 경우 반환하는 모든 요소로 새 배열을 생성한다.

문법

const array = [1, 2, 3, 4, 5];
const even = array.filter(item => item % 2 === 0);

console.log(even);
// 출력: [2, 4]

filter()는 조건에서 참인 경우에만 반환되는 배열을 생성하기 때문에 호출한 배열과 길이가 다를 수 있다는 점이 특징이다.

📖 reduce()

배열의 각 요소에 대해 주어진 리듀서(reducer)함수를 실행하고, 하나의 결과값을 반환한다. 배열을 축약할 때 유용

문법

const array = [1, 2, 3, 4, 5];
const sum = array.reduce((accumulator, current) => accumulator + current, 0);

console.log(sum);
// 출력: 15

reduce()의 경우 첫번째 인자를 함수를 전달하고, 두번째 인자로는 초기값을 설정한다. 다음 예시를 통해 자세히 알아보자.

예시

예시는 각 객체를 요소로 가지는 배열에서 name(key)과 example(value)만을 보유한 객체를 반환하는 예시이다.

// 배열 생성
const exampleArray = [
	{name: 'test1', example: 'example1', age: 20, desc: '...'},
	{name: 'test2', example: 'example2', age: 21, desc: '...'},
	{name: 'test3', example: 'example3', age: 22, desc: '...'},
	{name: 'test4', example: 'example4', age: 23, desc: '...'},
];

// reduce 사용
// prevObject : 이전 요소
// currentObject : 현재 요소
const nameAndExampleObject = exampleArray.reduce((prevObject, currentObject) => {
	prevObject = {
		...prevObject, // 스프레드 연산자 활용(객체에 누적된 데이터)
		currentObject[name]: currentObject.example
	};
	return prevObject
}, {}); // 두번째 인자로 빈 배열 부여

console.log(nameAndExampleObject);

// 결과 : {test1: example1, test2: example2, test3: example3, test4: example4 }

📖 find()

배열 내에서 주어진 팔변 함수를 만족하는 첫 번째 요소의 값을 반환한다. 해당하는 요소가 없는 경우 undifined를 반환한다.

문법

const array = [1, 2, 3, 4, 5];
const found = array.find(item => item > 3);
const wrongFound = array.find(item => item === 8);

console.log(found);
console.log(wrongFound);
// 출력 : 4
// 출력 : undifined

find()를 사용할 때 주의할 점은 찾고자하는 조건의 요소가 복수개일 경우 가장 첫 번째 요소가 반환된다는 것을 인지해야하며, 데이터가 없는 경우 undifined가 반환되기 때문에 조건문을 통한 분기처리 등에 주의깊게 사용해야한다.

📖 some()

배열의 적어도 하나의 요소가 주어진 판별 함수를 통화하는지 테스트하고 결과를 불린값을 반환한다.

문법

const array = [1, 2, 3, 4, 5];
// 짝수가 있는지 확인
const hasEvenNumber = array.some(item => item % 2 === 0);

console.log(hasEvenNumber);
// 출력: true

📖 every()

some과는 반대로 배열의 모든 요소가 주어진 판별 함수를 통과하는지 테스트하여 결과를 반환한다.

문법

const array = [2, 4, 6, 8, 10];
// 모든 요소가 짝수인지 확인
const allEven = array.every(item => item % 2 === 0);

console.log(allEven);
// 출력: true

⚡️ React 핵심 문법

📖 Props

부모 컴포넌트로부터 자식 컴포넌트로 데이터를 전달하는 경우 사용하며, 읽기 전용이다. 함수의 매개변수와 유사한 개념으로서 다양한 인스턴스에서 재사용 가능한 컴포넌트 생성이 가능하다.

문법

// props 객체 자체 전달
function SomeComponent (props) {...}
const SomeComponent = (props) => {...};

// 비구조화 할당 전달
function SomeComponent ({text, color}) {...}
const SomeComponent = ({text, color}) => {...};

// typescript 사용
interface SomeComponentProps {
	text: string;
	color: string;
	size: number;
}
const SomeComponent = ({
	text,
	color,
	size
}: SomeComponentProps):JSX.Element => { // 중요
	...
	return (...);
};

타입스크립트를 함께 사용하는 경우에는 //중요라는 표시가 되어있는 라인처럼 Props의 타입과 반환 값을 정확히 명시해주어야 컴포넌트에 대한 이해가 명확해지므로 반드시 정확한 타입을 매핑하고, 반환 값을 명시해주자.

예시

// props 인터페이스 정의(typescript 한정)
interface IButtonProps {
	text: string; // 버튼에 표시할 텍스트
	onClick: () => void; // 버튼의 이벤트 핸들러 함수
}

// 버튼 컴포넌트 정의
const CommonButton = ({text, onClick}:IButtonProps): JSX.Element => {
	return <button onClick={onClick}>{text}</button>
}

// 호출
const SomeComponent = (): JSX.Element => {
	const handleClick = () => {
		console.log('버튼 클릭');
	};
	return (
		<div>
			...
			<CommonButton
				text='버튼1'
				onClick={handleClick}
			/>
		</div>
	);
}

정리

props는 반복되어 생성되는 컴포넌트 혹은 초기 값을 부모 컴포넌트로부터 전달받아야 하는 경우 사용한다. 여기서 주의할 점은 props가 변경되면 컴포넌트는 리-렌더링 되기 때문에 props의 필요성을 잘 판단해서 사용해야한다.

📖 State

컴포넌트의 상태를 관리하는 데이터로 컴포넌트 내외부에 선언될 수 있으며 컴포넌트의 생명주기 동안 변경이 가능하다. 또한, State가 변경 시 컴포넌트는 리-렌더링된다.

문법

const [, 세터] = useState(초기값);

// 지역 State : 컴포넌트 내부
const [count, setCount] = useState(0);
// 전역 State : Context API, 라이브러리 등 활용
const [count, setCount] = useRecoilState(0);
// typescript 사용
const [count, setCount] = useState<number>(0);
setCount('2'); // type Error

예시

// 버튼 클릭 시 수량 증가 기능 구현
const CountComponent = ():JSX.Element => {
	// 지역 상태 선언 : 변경 시 마다 컴포넌트 리-렌더링
	const [count, setCount] = useState<number>(0);
	const handleCount = () => {
		// 연산이 필요한 state의 경우 아래와 같이 비동기적으로 업데이트 수행
		setCount(prev => prev + 1);
	};

	return (
		<div>
			<span>{count}</span>
			<button onClick={handleCount}>증가</button>
		</div>
	);
};

정리

위 예시에서 count가 변경되면 CountComponent는 리-렌더링이 발생한다. 아주 단순한 예시이기 때문에 state를 하나만 사용했지만 복합적인 컴포넌트에서 여러개의 state를 다룰 때는 리-렌더링이 불필요하게 일어날 수 있기 때문에 가급적이면 꼭 필요한 위치에서만 state를 선언해야한다.
만약, count가 CountComponent를 호출하는 상위 또는 차상위 컴포넌트에 있을 경우 count의 변경으로 인해 그와 무관한 다른 자식 컴포넌트들까지 리-렌더링이 발생할 수 있다. 이런 부분을 잘 고려해서 사용할 수 있도록 하자.

📖 useEffect

컴포넌트가 렌더링 될 때마다 특정 작업을 수행할 수 있게 하며, 첫 렌더링과 업데이트 시마다 호출되는 내장 훅 함수이다. 또한, 특정 데이터를 의존성 배열에 추가하여 해당 데이터 변경시에도 호출이 가능하다.

문법

// 생김새
useEffect(함수, 의존성배열);

// 최초 렌더링 시 한번만 수행 : 빈 배열
useEffect(() => {...}, []);

// 특정 데이터 변경 시 수행 : props, state 등
const [disabled, setDisabled] = useState<boolean>(false);
useEffect(() => {setDisabled(!disabled)}, [disabled]);

// 복수 데이터 변경 시 수행
useEffect(() => {
	if(데이터1) {
		console.log(데이터1);
	}
	....
}, [데이터1, 데이터2, 데이터3]);

// 클린 업 함수 수행 : 컴포넌트 언마운트(제거) 시
useEffect(() => {
	// return 값에 실행하고자하는 작업을 반드시 함수형으로 선언
	return () => {
		console.log('컴포넌트 언마운트 시 수행');
	}
}, []);

예시

const SomeComponent = ():JSX.Element => {
	// 초기 값 미부여
	const [text, setText] = useState<string>('');

	// 최초 렌더링 시 데이터 변경
	useEffect(() => {
		setText('useEffect 실행');
	}, []);

	return (
		<div>{text}</div>
	);
};

정리

useEffect는 리액트의 클래스형 컴포넌트에서 지원하던 생명주기 함수와 유사한 기능을 하는 내장 훅 함수라고 인식하면 된다. 컴포넌트가 최초 마운트 되거나 언마운트시에 수행할 동작을 정의해주고, 특정 데이터의 변경에 따라 자동으로 실행되도록 의존성 배열을 추가하면되니 굉장히 도움이 많이되고 유용한 내장 훅 함수이다. 하지만 무분별하게 사용할 경우 데이터 변경에 따른 동작을 유추하기가 어려워지고, 의도하지 않은대로 동작하여 사이드 이펙트가 발생할 가능성이 높아지기 때문에 꼭 필요한지 여부를 여러번 검토하고 적용해야할 필요성이 있다.

profile
서핑하는 개발자🏄🏽

0개의 댓글