-
21. Component Composition (컴포넌트 구성)
-
22. Dynamic Imports (동적 임포트)
-
23. Context with useReducer (useReducer와 컨텍스트 사용)
-
24. Forwarding Refs (Refs 전달)
-
25. Using Refs for Focus Management (Refs를 사용한 포커스 관리)
-
26. Handling Asynchronous Calls with useEffect (useEffect를 사용한 비동기 호출 처리)
-
27. Debouncing in Functional Components (함수형 컴포넌트에서 디바운싱)
-
28. Throttling in Functional Components (함수형 컴포넌트에서 스로틀링)
-
29. Component Lifecycle with useEffect (useEffect를 사용한 컴포넌트 생명주기 관리)
-
30. Persisting State with Local Storage (로컬 스토리지를 사용한 상태 유지)
-
자주 사용하는 특징(react 18버전과 비교)
-
잘 사용되지 않는 특징
위 글은 50 React.js Super Hacks Every Developer Should Know를 번역 겸 약간의 각색을 곁들인 글로,
이 글은 5번째 중 3번째 글이다.
21. Component Composition (컴포넌트 구성)
문제: 복잡한 컴포넌트를 단순한 컴포넌트로부터 빌드하여 코드 재사용성과 가독성을 높여야 합니다.
해결책: 컴포넌트 구성을 통해 단순한 컴포넌트를 결합하여 복잡한 컴포넌트를 빌드합니다.
// PROBLEM: 단순한 컴포넌트가 각각 따로 존재하여 관리가 어려움
const Header = () => <header>Header</header>;
const Content = () => <main>Content</main>;
const Footer = () => <footer>Footer</footer>;
// SOLUTION: 컴포넌트 구성을 사용하여 복잡한 컴포넌트 빌드
const Header = () => <header>Header</header>;
const Content = () => <main>Content</main>;
const Footer = () => <footer>Footer</footer>;
const Layout = () => (
<div>
<Header />
<Content />
<Footer />
</div>
);
// 사용 예시
<Layout />
22. Dynamic Imports (동적 임포트)
문제: 애플리케이션의 초기 로드 시간을 개선하기 위해 컴포넌트를 동적으로 로드하고 싶습니다.
해결책: 동적 임포트를 사용하여 필요한 경우에만 컴포넌트를 로드합니다.
// PROBLEM: 모든 컴포넌트를 한 번에 로드하여 초기 로드 시간이 길어짐
import MyComponent from './MyComponent';
// SOLUTION: 동적 임포트를 사용하여 필요한 경우에만 컴포넌트를 로드
import React, { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
const App = () => (
<Suspense fallback={<div>Loading…</div>}>
<LazyComponent />
</Suspense>
);
// 사용 예시
<App />
23. Context with useReducer (useReducer와 컨텍스트 사용)
문제: 여러 컴포넌트에서 복잡한 상태 로직을 관리하기 어렵습니다.
해결책: useReducer
와 컨텍스트 API를 결합하여 복잡한 상태 로직을 효과적으로 관리합니다.
// PROBLEM: 복잡한 상태 로직을 여러 컴포넌트에서 개별적으로 관리
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
// SOLUTION: useReducer와 컨텍스트 API를 결합하여 상태 관리
const CountContext = React.createContext();
const CountProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<CountContext.Provider value={{ state, dispatch }}>
{children}
</CountContext.Provider>
);
};
const Counter = () => {
const { state, dispatch } = useContext(CountContext);
return (
<div>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
};
// 사용 예시
<CountProvider>
<Counter />
</CountProvider>
24. Forwarding Refs (Refs 전달)
문제: 컴포넌트를 통해 자식에게 ref를 전달해야 합니다.
해결책: React.forwardRef
를 사용하여 ref를 자식 컴포넌트에 전달합니다.
// PROBLEM: 컴포넌트가 ref를 직접 접근할 수 없음
const Button = (props) => (
<button className="fancy-button">
{props.children}
</button>
);
// SOLUTION: React.forwardRef를 사용하여 ref 전달
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="fancy-button">
{props.children}
</button>
));
// 사용 예시
const ref = React.createRef();
<FancyButton ref={ref}>Click me</FancyButton>
25. Using Refs for Focus Management (Refs를 사용한 포커스 관리)
문제: 컴포넌트가 마운트될 때 입력 필드에 포커스를 주어야 합니다.
해결책: refs를 사용하여 프로그램적으로 포커스를 관리합니다.
// PROBLEM: 입력 필드에 포커스를 프로그램적으로 줄 수 없음
const Input = () => (
<input type="text" />
);
// SOLUTION: refs를 사용하여 포커스를 프로그램적으로 관리
const FocusInput = () => {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <input ref={inputRef} />;
};
// 사용 예시
<FocusInput />
26. Handling Asynchronous Calls with useEffect (useEffect를 사용한 비동기 호출 처리)
문제: 컴포넌트 내에서 데이터를 가져오는 비동기 작업을 처리해야 합니다.
해결책: useEffect
훅을 사용하여 비동기 호출을 처리하고 컴포넌트 생명주기를 관리합니다.
// PROBLEM:비동기 작업을 컴포넌트 생명주기와 함께 관리하기 어려움
const fetchData = async (url) => {
const response = await fetch(url);
const result = await response.json();
return result;
};
// SOLUTION: useEffect 훅을 사용하여 비동기 호출 처리
const DataFetcher = ({ url }) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const response = await fetch(url);
const result = await response.json();
setData(result);
setLoading(false);
};
fetchData();
}, [url]);
return loading ? <div>Loading…</div> : <div>{data.title}</div>;
};
// 사용 예시
<DataFetcher url="https://api.example.com/data" />
27. Debouncing in Functional Components (함수형 컴포넌트에서 디바운싱)
문제: 입력 처리를 최적화하여 너무 많은 리렌더링이나 API 호출을 방지해야 합니다.
해결책: 함수형 컴포넌트 내에서 디바운스 함수를 사용하여 함수 실행 속도를 제한합니다.
// PROBLEM: 입력이 너무 자주 발생하여 성능 저하
const SearchInput = () => {
const [query, setQuery] = useState('');
useEffect(() => {
console.log(`Searching for ${query}`);
}, [query]);
return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
};
// SOLUTION: 디바운스를 사용하여 함수 실행 속도를 제한
import { useState, useEffect } from 'react';
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
// 사용 예시
const SearchInput = () => {
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 500);
useEffect(() => {
if (debouncedQuery) {
console.log(`Searching for ${debouncedQuery}`);
}
}, [debouncedQuery]);
return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
};
28. Throttling in Functional Components (함수형 컴포넌트에서 스로틀링)
문제: 스크롤 등의 기능을 위해 함수 실행 빈도를 제한해야 합니다.
해결책: 함수형 컴포넌트 내에서 스로틀 함수를 사용하여 함수 실행 속도를 제한합니다.
// PROBLEM: 스크롤 이벤트가 너무 자주 발생하여 성능 저하
const ScrollComponent = () => {
const handleScroll = () => {
console.log('Scroll event');
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return <div>Scroll to see throttling in action</div>;
};
// SOLUTION: 스로틀 함수를 사용하여 함수 실행 속도를 제한
import { useCallback, useEffect, useRef } from 'react';
const useThrottle = (callback, delay) => {
const lastCall = useRef(0);
return useCallback((...args) => {
const now = new Date().getTime();
if
(now - lastCall.current >= delay) {
lastCall.current = now;
callback(...args);
}
}, [callback, delay]);
};
// 사용 예시
const ScrollComponent = () => {
const handleScroll = useThrottle(() => {
console.log('Scroll event');
}, 1000);
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, [handleScroll]);
return <div>Scroll to see throttling in action</div>;
};
29. Component Lifecycle with useEffect (useEffect를 사용한 컴포넌트 생명주기 관리)
문제: 컴포넌트의 생명주기 단계(마운트, 업데이트, 언마운트)를 처리해야 합니다.
해결책: useEffect
훅을 사용하여 컴포넌트 생명주기 메서드를 시뮬레이션합니다.
// PROBLEM: 클래스 컴포넌트에서 생명주기 메서드 사용
class LifecycleComponent extends React.Component {
componentDidMount() {
console.log('Component did mount');
}
componentWillUnmount() {
console.log('Component will unmount');
}
render() {
return <div>Lifecycle Demo</div>;
}
}
// SOLUTION: useEffect를 사용하여 생명주기 메서드 시뮬레이션
const LifecycleComponent = () => {
useEffect(() => {
console.log('Component did mount');
return () => {
console.log('Component will unmount');
};
}, []);
useEffect(() => {
console.log('Component did update');
});
return <div>Lifecycle Demo</div>;
};
// 사용 예시
<LifecycleComponent />
30. Persisting State with Local Storage (로컬 스토리지를 사용한 상태 유지)
문제: 페이지가 새로 고쳐져도 컴포넌트 상태를 유지해야 합니다.
해결책: 로컬 스토리지를 사용하여 상태를 유지합니다.
// PROBLEM: 페이지 새로고침 시 상태가 초기화됨
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
// SOLUTION: 로컬 스토리지를 사용하여 상태 유지
import { useState, useEffect } from 'react';
const useLocalStorage = (key, initialValue) => {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value) => {
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
};
// 사용 예시
const Counter = () => {
const [count, setCount] = useLocalStorage('count', 0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
자주 사용하는 특징(react 18버전과 비교)
- Component Composition (컴포넌트 구성):
- 컴포넌트를 작은 단위로 쪼개어 재사용하고 조합하는 것은 React의 기본 철학 중 하나입니다.
- Dynamic Imports (동적 임포트):
- 특히, 큰 애플리케이션에서 초기 로드 시간을 최적화하기 위해 동적 임포트가 많이 사용됩니다.
- Context with useReducer (useReducer와 컨텍스트 사용):
- 복잡한 상태 관리가 필요한 경우 여전히 유용합니다. useReducer와 Context API를 결합하여 상태 관리를 하는 패턴은 매우 흔합니다.
- Handling Asynchronous Calls with useEffect (useEffect를 사용한 비동기 호출 처리):
- 비동기 작업 처리를 위해 여전히 많이 사용됩니다. 데이터를 가져오거나, 외부 API와 통신할 때 useEffect를 사용하는 것은 React 18에서도 일반적인 패턴입니다.
- Debouncing in Functional Components (함수형 컴포넌트에서 디바운싱):
- 입력 필드 최적화를 위해 자주 사용됩니다. 입력이 자주 발생하는 경우 성능 최적화를 위해 디바운싱은 여전히 유용합니다.
- Component Lifecycle with useEffect (useEffect를 사용한 컴포넌트 생명주기 관리):
- 컴포넌트 생명주기 관리를 위해 여전히 사용됩니다. useEffect는 클래스 컴포넌트의 생명주기 메서드를 대체하는 중요한 훅으로 React 18에서도 필수적입니다.
- Persisting State with Local Storage (로컬 스토리지를 사용한 상태 유지):
- 상태 유지에 많이 사용됩니다. 페이지 새로고침 후에도 상태를 유지해야 하는 경우, 로컬 스토리지를 사용하는 패턴은 여전히 유효합니다.
잘 사용되지 않는 특징
- Forwarding Refs (Refs 전달):
- 특정 상황에서만 사용됩니다. 직접 DOM 접근이 필요한 경우가 많지 않기 때문에, 이 패턴은 일반적인 컴포넌트에서는 덜 사용될 수 있습니다.
- Using Refs for Focus Management (Refs를 사용한 포커스 관리):
- 특정 요구사항이 있을 때만 사용됩니다. 포커스 관리는 일반적으로 필요한 경우가 적기 때문에, 자주 사용되지는 않습니다.
- Throttling in Functional Components (함수형 컴포넌트에서 스로틀링):
- 특정 상황에서만 사용됩니다. 스크롤이나 리사이즈 이벤트와 같이 빈번하게 발생하는 이벤트에서만 필요합니다. 일반적인 경우에는 덜 사용될 수 있습니다.
- Higher-Order Components (HOCs) (고차 컴포넌트):
- React 18에서 점점 덜 사용되고 있습니다. 대신 훅을 사용한 로직 재사용이 더 많이 사용됩니다. HOC는 복잡성을 증가시키기 때문에 최신 코드베이스에서는 훅을 선호하는 경향이 있습니다.
관련 글
2024.06.13 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (1)
[React] React 개발을 하며 지키면 좋을 것들 (1)
2024.06.15 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (3)2024.06.13 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (1)2024.06.09 - [Programming Language/Javascript] - [JS
juniortunar.tistory.com
2024.06.14 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (2)
[React] React 개발을 하며 지키면 좋을 것들 (2)
위 글은 50 React.js Super Hacks Every Developer Should Know를 번역 겸 약간의 각색을 곁들인 글로,팁이 50가지나 되는 만큼 한 글에 담기보단 10개씩 5번으로 나눠서 포스팅할 예정이다.이 글은 5번째
juniortunar.tistory.com
2024.06.16 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (4)
[React] React 개발을 하며 지키면 좋을 것들 (4)
위 글은 50 React.js Super Hacks Every Developer Should Know를 번역 겸 약간의 각색을 곁들인 글로,이 글은 5번째 중 4번째 글이다.31. Custom Hooks for Fetching Data (데이터 가져오기 위한 커스텀 훅)문제: 여러 컴포
juniortunar.tistory.com
2024.06.17 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (5)
[React] React 개발을 하며 지키면 좋을 것들 (5)
위 글은 50 React.js Super Hacks Every Developer Should Know를 번역 겸 약간의 각색을 곁들인 글로,이 글은 5번째 중 5번째(마지막) 글이다.41. Static Site Generation (SSG) with Next.js (Next.js를 사용한 정적 사이트 생
juniortunar.tistory.com
위 글은 50 React.js Super Hacks Every Developer Should Know를 번역 겸 약간의 각색을 곁들인 글로,
이 글은 5번째 중 3번째 글이다.
21. Component Composition (컴포넌트 구성)
문제: 복잡한 컴포넌트를 단순한 컴포넌트로부터 빌드하여 코드 재사용성과 가독성을 높여야 합니다.
해결책: 컴포넌트 구성을 통해 단순한 컴포넌트를 결합하여 복잡한 컴포넌트를 빌드합니다.
// PROBLEM: 단순한 컴포넌트가 각각 따로 존재하여 관리가 어려움
const Header = () => <header>Header</header>;
const Content = () => <main>Content</main>;
const Footer = () => <footer>Footer</footer>;
// SOLUTION: 컴포넌트 구성을 사용하여 복잡한 컴포넌트 빌드
const Header = () => <header>Header</header>;
const Content = () => <main>Content</main>;
const Footer = () => <footer>Footer</footer>;
const Layout = () => (
<div>
<Header />
<Content />
<Footer />
</div>
);
// 사용 예시
<Layout />
22. Dynamic Imports (동적 임포트)
문제: 애플리케이션의 초기 로드 시간을 개선하기 위해 컴포넌트를 동적으로 로드하고 싶습니다.
해결책: 동적 임포트를 사용하여 필요한 경우에만 컴포넌트를 로드합니다.
// PROBLEM: 모든 컴포넌트를 한 번에 로드하여 초기 로드 시간이 길어짐
import MyComponent from './MyComponent';
// SOLUTION: 동적 임포트를 사용하여 필요한 경우에만 컴포넌트를 로드
import React, { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
const App = () => (
<Suspense fallback={<div>Loading…</div>}>
<LazyComponent />
</Suspense>
);
// 사용 예시
<App />
23. Context with useReducer (useReducer와 컨텍스트 사용)
문제: 여러 컴포넌트에서 복잡한 상태 로직을 관리하기 어렵습니다.
해결책: useReducer
와 컨텍스트 API를 결합하여 복잡한 상태 로직을 효과적으로 관리합니다.
// PROBLEM: 복잡한 상태 로직을 여러 컴포넌트에서 개별적으로 관리
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
// SOLUTION: useReducer와 컨텍스트 API를 결합하여 상태 관리
const CountContext = React.createContext();
const CountProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<CountContext.Provider value={{ state, dispatch }}>
{children}
</CountContext.Provider>
);
};
const Counter = () => {
const { state, dispatch } = useContext(CountContext);
return (
<div>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
};
// 사용 예시
<CountProvider>
<Counter />
</CountProvider>
24. Forwarding Refs (Refs 전달)
문제: 컴포넌트를 통해 자식에게 ref를 전달해야 합니다.
해결책: React.forwardRef
를 사용하여 ref를 자식 컴포넌트에 전달합니다.
// PROBLEM: 컴포넌트가 ref를 직접 접근할 수 없음
const Button = (props) => (
<button className="fancy-button">
{props.children}
</button>
);
// SOLUTION: React.forwardRef를 사용하여 ref 전달
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="fancy-button">
{props.children}
</button>
));
// 사용 예시
const ref = React.createRef();
<FancyButton ref={ref}>Click me</FancyButton>
25. Using Refs for Focus Management (Refs를 사용한 포커스 관리)
문제: 컴포넌트가 마운트될 때 입력 필드에 포커스를 주어야 합니다.
해결책: refs를 사용하여 프로그램적으로 포커스를 관리합니다.
// PROBLEM: 입력 필드에 포커스를 프로그램적으로 줄 수 없음
const Input = () => (
<input type="text" />
);
// SOLUTION: refs를 사용하여 포커스를 프로그램적으로 관리
const FocusInput = () => {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <input ref={inputRef} />;
};
// 사용 예시
<FocusInput />
26. Handling Asynchronous Calls with useEffect (useEffect를 사용한 비동기 호출 처리)
문제: 컴포넌트 내에서 데이터를 가져오는 비동기 작업을 처리해야 합니다.
해결책: useEffect
훅을 사용하여 비동기 호출을 처리하고 컴포넌트 생명주기를 관리합니다.
// PROBLEM:비동기 작업을 컴포넌트 생명주기와 함께 관리하기 어려움
const fetchData = async (url) => {
const response = await fetch(url);
const result = await response.json();
return result;
};
// SOLUTION: useEffect 훅을 사용하여 비동기 호출 처리
const DataFetcher = ({ url }) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const response = await fetch(url);
const result = await response.json();
setData(result);
setLoading(false);
};
fetchData();
}, [url]);
return loading ? <div>Loading…</div> : <div>{data.title}</div>;
};
// 사용 예시
<DataFetcher url="https://api.example.com/data" />
27. Debouncing in Functional Components (함수형 컴포넌트에서 디바운싱)
문제: 입력 처리를 최적화하여 너무 많은 리렌더링이나 API 호출을 방지해야 합니다.
해결책: 함수형 컴포넌트 내에서 디바운스 함수를 사용하여 함수 실행 속도를 제한합니다.
// PROBLEM: 입력이 너무 자주 발생하여 성능 저하
const SearchInput = () => {
const [query, setQuery] = useState('');
useEffect(() => {
console.log(`Searching for ${query}`);
}, [query]);
return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
};
// SOLUTION: 디바운스를 사용하여 함수 실행 속도를 제한
import { useState, useEffect } from 'react';
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
// 사용 예시
const SearchInput = () => {
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 500);
useEffect(() => {
if (debouncedQuery) {
console.log(`Searching for ${debouncedQuery}`);
}
}, [debouncedQuery]);
return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
};
28. Throttling in Functional Components (함수형 컴포넌트에서 스로틀링)
문제: 스크롤 등의 기능을 위해 함수 실행 빈도를 제한해야 합니다.
해결책: 함수형 컴포넌트 내에서 스로틀 함수를 사용하여 함수 실행 속도를 제한합니다.
// PROBLEM: 스크롤 이벤트가 너무 자주 발생하여 성능 저하
const ScrollComponent = () => {
const handleScroll = () => {
console.log('Scroll event');
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return <div>Scroll to see throttling in action</div>;
};
// SOLUTION: 스로틀 함수를 사용하여 함수 실행 속도를 제한
import { useCallback, useEffect, useRef } from 'react';
const useThrottle = (callback, delay) => {
const lastCall = useRef(0);
return useCallback((...args) => {
const now = new Date().getTime();
if
(now - lastCall.current >= delay) {
lastCall.current = now;
callback(...args);
}
}, [callback, delay]);
};
// 사용 예시
const ScrollComponent = () => {
const handleScroll = useThrottle(() => {
console.log('Scroll event');
}, 1000);
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, [handleScroll]);
return <div>Scroll to see throttling in action</div>;
};
29. Component Lifecycle with useEffect (useEffect를 사용한 컴포넌트 생명주기 관리)
문제: 컴포넌트의 생명주기 단계(마운트, 업데이트, 언마운트)를 처리해야 합니다.
해결책: useEffect
훅을 사용하여 컴포넌트 생명주기 메서드를 시뮬레이션합니다.
// PROBLEM: 클래스 컴포넌트에서 생명주기 메서드 사용
class LifecycleComponent extends React.Component {
componentDidMount() {
console.log('Component did mount');
}
componentWillUnmount() {
console.log('Component will unmount');
}
render() {
return <div>Lifecycle Demo</div>;
}
}
// SOLUTION: useEffect를 사용하여 생명주기 메서드 시뮬레이션
const LifecycleComponent = () => {
useEffect(() => {
console.log('Component did mount');
return () => {
console.log('Component will unmount');
};
}, []);
useEffect(() => {
console.log('Component did update');
});
return <div>Lifecycle Demo</div>;
};
// 사용 예시
<LifecycleComponent />
30. Persisting State with Local Storage (로컬 스토리지를 사용한 상태 유지)
문제: 페이지가 새로 고쳐져도 컴포넌트 상태를 유지해야 합니다.
해결책: 로컬 스토리지를 사용하여 상태를 유지합니다.
// PROBLEM: 페이지 새로고침 시 상태가 초기화됨
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
// SOLUTION: 로컬 스토리지를 사용하여 상태 유지
import { useState, useEffect } from 'react';
const useLocalStorage = (key, initialValue) => {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value) => {
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
};
// 사용 예시
const Counter = () => {
const [count, setCount] = useLocalStorage('count', 0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
자주 사용하는 특징(react 18버전과 비교)
- Component Composition (컴포넌트 구성):
- 컴포넌트를 작은 단위로 쪼개어 재사용하고 조합하는 것은 React의 기본 철학 중 하나입니다.
- Dynamic Imports (동적 임포트):
- 특히, 큰 애플리케이션에서 초기 로드 시간을 최적화하기 위해 동적 임포트가 많이 사용됩니다.
- Context with useReducer (useReducer와 컨텍스트 사용):
- 복잡한 상태 관리가 필요한 경우 여전히 유용합니다. useReducer와 Context API를 결합하여 상태 관리를 하는 패턴은 매우 흔합니다.
- Handling Asynchronous Calls with useEffect (useEffect를 사용한 비동기 호출 처리):
- 비동기 작업 처리를 위해 여전히 많이 사용됩니다. 데이터를 가져오거나, 외부 API와 통신할 때 useEffect를 사용하는 것은 React 18에서도 일반적인 패턴입니다.
- Debouncing in Functional Components (함수형 컴포넌트에서 디바운싱):
- 입력 필드 최적화를 위해 자주 사용됩니다. 입력이 자주 발생하는 경우 성능 최적화를 위해 디바운싱은 여전히 유용합니다.
- Component Lifecycle with useEffect (useEffect를 사용한 컴포넌트 생명주기 관리):
- 컴포넌트 생명주기 관리를 위해 여전히 사용됩니다. useEffect는 클래스 컴포넌트의 생명주기 메서드를 대체하는 중요한 훅으로 React 18에서도 필수적입니다.
- Persisting State with Local Storage (로컬 스토리지를 사용한 상태 유지):
- 상태 유지에 많이 사용됩니다. 페이지 새로고침 후에도 상태를 유지해야 하는 경우, 로컬 스토리지를 사용하는 패턴은 여전히 유효합니다.
잘 사용되지 않는 특징
- Forwarding Refs (Refs 전달):
- 특정 상황에서만 사용됩니다. 직접 DOM 접근이 필요한 경우가 많지 않기 때문에, 이 패턴은 일반적인 컴포넌트에서는 덜 사용될 수 있습니다.
- Using Refs for Focus Management (Refs를 사용한 포커스 관리):
- 특정 요구사항이 있을 때만 사용됩니다. 포커스 관리는 일반적으로 필요한 경우가 적기 때문에, 자주 사용되지는 않습니다.
- Throttling in Functional Components (함수형 컴포넌트에서 스로틀링):
- 특정 상황에서만 사용됩니다. 스크롤이나 리사이즈 이벤트와 같이 빈번하게 발생하는 이벤트에서만 필요합니다. 일반적인 경우에는 덜 사용될 수 있습니다.
- Higher-Order Components (HOCs) (고차 컴포넌트):
- React 18에서 점점 덜 사용되고 있습니다. 대신 훅을 사용한 로직 재사용이 더 많이 사용됩니다. HOC는 복잡성을 증가시키기 때문에 최신 코드베이스에서는 훅을 선호하는 경향이 있습니다.
관련 글
2024.06.13 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (1)
[React] React 개발을 하며 지키면 좋을 것들 (1)
2024.06.15 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (3)2024.06.13 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (1)2024.06.09 - [Programming Language/Javascript] - [JS
juniortunar.tistory.com
2024.06.14 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (2)
[React] React 개발을 하며 지키면 좋을 것들 (2)
위 글은 50 React.js Super Hacks Every Developer Should Know를 번역 겸 약간의 각색을 곁들인 글로,팁이 50가지나 되는 만큼 한 글에 담기보단 10개씩 5번으로 나눠서 포스팅할 예정이다.이 글은 5번째
juniortunar.tistory.com
2024.06.16 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (4)
[React] React 개발을 하며 지키면 좋을 것들 (4)
위 글은 50 React.js Super Hacks Every Developer Should Know를 번역 겸 약간의 각색을 곁들인 글로,이 글은 5번째 중 4번째 글이다.31. Custom Hooks for Fetching Data (데이터 가져오기 위한 커스텀 훅)문제: 여러 컴포
juniortunar.tistory.com
2024.06.17 - [Programming Language/React] - [React] React 개발을 하며 지키면 좋을 것들 (5)
[React] React 개발을 하며 지키면 좋을 것들 (5)
위 글은 50 React.js Super Hacks Every Developer Should Know를 번역 겸 약간의 각색을 곁들인 글로,이 글은 5번째 중 5번째(마지막) 글이다.41. Static Site Generation (SSG) with Next.js (Next.js를 사용한 정적 사이트 생
juniortunar.tistory.com