[React] Udemy 강의 노트 10-2

2023. 2. 9. 22:56WEB Dev/StudyNote

728x90

 

 

useReducer & useEffect

- 입력은 전체 폼의 일부이다.

- 코드가 너무 일찍 실행된 경우에는 useEffect는 state 업데이트 후에만 실행됐었다.

- 의존성은 state 전체이지 유효성이 아니다.

- 객체의 특정 속성을 추출하는 객체 디스트럭처링을 이용할 수 있다. 

- const { isValid: emailIsValid } = emailState; 로 emailState의 isValid state를 emailIsVaild라는 상수로 별칭할당을 할 수 있다.

 

 

중첩 속성을 useEffect에 종속성으로 추가하기

- useEffect()에 객체 속성을 종속성으로 추가하기 위해 distructuring을 사용 

const { someProperty } = someObject;
useEffect(()=>{
  //code that only uses someProperty...
}, [someProperty])

- 매우 일반적인 패턴 및 접근 방식

- 핵심은 전체 개체 대신 특정 속성을 종속성으로 전달한다는 것

- 코드는 아래와 같이 작성할 수도 있지만 그것보다 위와 같이 someProperty를 종속성으로 전달하는 것을 추천한다.

- 이유는 useEffect 훅은 someObject가 변경될 때마다 재실행되기 때문이다. (someObject는 단일 속성이 아니기 때문)

useEffect(()=>{
  
}, [someObject])

 

 

 

State 관리를 위한 useReducer 대 useState

- 일반적으로 useReducer가 필요한 때는 useState를 이용하면 너무 많은 일을 처리해야 해서 번거로워질 때다. 

- useState는 주요 state 관리 툴이다.

- 개별 state 및 데이터들을 다루기에 적합하다.

- state 업데이트가 쉽고 몇 개 되지 않을 때 추천한다.

- 만약 state로서의 객체나 복잡한 state가 있으면 useReducer를 고려할 수 있다.

- 연관된 state 조각들로 구성된 관련 데이터를 다루는 경우이다.

- 특히 폼이나 인풋 등의 state에 권장한다.

- state 하나를 변경하는 여러 다른 액션이 있을 때도 권장한다.

 

 

 

 

 

 

리액트 Context (Context API) 소개

- 프롭스를 통해 많은 컴포넌트를 거쳐 스테이트를 관리할 때 생기는 문제

- state를 여러 컴포넌트를 통해 전달하는 경우 props를 이용한다.

- 하위 컴포넌트들 사이에서 연속되는 관계가 없지만 state를 전달해야 할 때 모든 컴포넌트에 접근할 수 있는 가장 상위인 App 컴포넌트를 사용하게 되면서 전혀 상관없는 컴포넌트들을 거쳐 state를 전달하게 된다. -> 프롭 체인 prop chain !!!

 

 

- 부모를 통해 데이터를 전달하지 않도록 해야한다.

- 이를 위해 리액트에 내장된 내부적인 state 저장소가 있다.

 

 

 

 

리액트 컨텍스트 API 사용

- 리액트 내의 context는 state를 관리하게 해주는 거으로 앱의 어떤 컴포넌트에서 다른 컴포넌트로 직접 state를 전달하게 해준다.

- React.createContext()로 컨텍스트 객체를 생성한다. 

- createContext는 기본 컨텍스트를 만든다. 대부분의 경우에 객체이다.

- 이 객체를 변수에 담아 export 하여 내보낼 수 있다.

- 리액트가 context를 사용하기 위해 해야할 일은 먼저 공급해야 하고, 접근 권한이 있어야 한다.

- 공급은 항상 첫 번째로 해야 하는 일로 그 컨텍스트를 활용할 수 있어야 하는 모든 컴포넌트를 JSX 코드로 감싸는 것을 말한다. 

- JSX 코드 내에서 .을 이용해 provider에 접근할 수 있다.<AuthContext.provider>

- 이를 이용해 다른 컴포넌트 및 자손 컴포넌트는 해당 컨텍스트에 접근할 수 있다.

- 값에 접근하려면 리스닝 해야 하는데 두 가지 방법으로 리스닝 할 수 있다.

- context 소비자(Consumer) 또는 리액트 훅을 사용한다.

- 일반적으로 리액트 훅을 사용한다.

- consumer은 함수를 자식으로 가진다. 

- 기본값은 공급자 없이 소비하는 경우에만 사용된다. 

 

 

 

useContext 훅으로 컨텍스트에 탭핑(tapping)하기

- useContext 훅은 컨텍스트를 사용할 수 있게 해준다.

- 리액트 컴포넌트 함수에서 useContext를 호출하고 컨텍스트에게 사용하려는 컨텍스트를 가리키는 포인터를 전달한다. 

- const ctx = useContext(AuthContext);

 

 

 

컨텍스트를 동적으로 만들기

- value에 함수를 가리키도록 할 수 있다.

- props는 컴포넌트를 구성하고 그것들을 재사용할 수 있도록 하는 매커니즘

- 따라서 많은 컴포넌트를 통해 전달하고자 하는 것이 있는 경우에만, 그리고 매우 특정적인 일을 하는 컴포넌트로 전달하는 경우에만 컨텍스트를 사용하는 것이 좋다.

 

 

 

사용자 정의 컨텍스트 제공자 구성요소 빌드 및 사용

- VSCode는 기본 context 객체를 보고 컨텍스트에서 접근할 수 있는 것을 찾기 때문에 provider value에 값을 넣더라도 기본 context 객체에 선언해주면 편하게 쓸 수 있다.

- 전체 인증 state를 별도의 공급자 컴포넌트 (auth-context.js)에서 관리할 수 있다.

 

 

 

리액트 컨텍스트 제한

- 리액트 컨텍스트는 앱 전체 또는 컴포넌트 전체 state에는 적합할 수 있다.  (여러 컴포넌트에 영향을 미치는 state)

- 매 초 또는 1초에 여러번 state가 변경되는 경우처럼 변경이 잦은 경우에는 리액트 컨텍스트는 적합하지 않다.

- 몇 분에 한 번씩 바뀌는 경우는 컨텍스트를 쓸 수 있다.

- 앱 전체 또는 컴포넌트 전체에 걸쳐 state가 자주 변경되는 경우에는 더 나은 도구가 있다. 이것이 리덕스이다.

- 프롭의 모든 커뮤니케이션을 컨텍스트가 대체할 수 없다.

- 긴 프롭 체인을 교체하기 위해서는 고려할 만 하다.

 

 

 

 

"Hook의 규칙" 배우기

- 두 개의 메인 규칙

- 리액트 훅은 use로 시작하는 모든 함수로 리액트 훅은 리액트 함수에서만 호출해야한다. (리액트 컴포넌트 함수)

- 또는 사용자 정의 훅에서도 호출할 수 있다.

- 두 번째는 리액트 훅은 리액트 컴포넌트 함수 또는 사용자 정의 훅 함수의 최상위 수준에서만 호출해야 한다. 

- 중첩문이나 block 문, 조건문, 훅 안에서 훅을 호출해서는 안된다.

- 특정 훅인 useEffect는 참조하는 모든 항목을 의존성으로 useEffect 내부에 추가해야 한다.

- useReducer 또는 useState에 의해 노출된 state 업데이트 함수는 변경되지 않도록 리액트가 보장한다.

- 브라우저에서 오지 않거나 또는 컴포넌트 함수 외부에서 오는 데이터들 외에 useEffect를 사용하는 컴포넌트 함수 내부에서 오는 데이터들은 의존성 배열로 가야 한다.

 

 

 

 

 

입력 컴포넌트 리팩토링

 

Forward Refs 에 대해 알아보기

- input 컴포넌트와 명령형으로 상호작용하게 해준다.

- 어떤 state를 전달해서 그 컴포넌트에서 뭔가를 변경하는 것이 아니라 컴포넌트 내부에서 함수를 호출하는 방식

- 일반적인 리액트 패턴은 아니다.

- 일반적인 input이라면 ref를 사용하면 된다.

- 함수 컴포넌트는 ref를 받을 수 없다 Function components cannot be given refs.

- 그래서 ref를 사용할 수 없고 props 객체에서 ref prop을 받아들이지 않는다.

- 제대로 작동시키기 위해서는 input 컴포넌트에서 useImperativeHandle 훅을 import 한다.

- useImperativeHandle은 컴포넌트나 컴포넌트 내부에서 오는 기능들을 명령적으로 사용할 수 있게 해준다.

- 일반적인 state 프롭 관리를 통하지 않고 부모 컴포넌트의 state로 컴포넌트를 제어하지 않고 프로그래밍적으로 컴포넌트에서 직접 호출하거나 조작하게 해준다.

- useImperativeHandle을 호출하고 두 가지를 넣어준다 

- 첫 번째 인자는 컴포넌트에서 props를 받아오는 것 처럼 ref를 받아와서 넣어준다.

- 두 번째 인자인 함수에서 반환하는 것은 객체여야 하고 이 객체는 외부에서 사용할 수 있는 모든 데이터를 포함한다.

- ref 를 활성화 시키려면 input 컴포넌트 함수를 특별한 방법으로 내보내야 한다.

- React.forwardRef로 감싸준다.

 

 

const Input = React.forwardRef((props, ref) => {
	const inputRef = useRef(); 

	const activate = () => {
		inputRef.current.focus();
	}

	useImperativeHandle( ref , ()=>{
		return {
			focus: activate,
		}
	});

	return (
		<div
		className={`${classes.control} ${
			props.isValid === false ? classes.invalid : ''
		}`}
	>
		<label htmlFor={props.id}>{props.label}</label>
		<input
		  ref={inputRef}
			type={props.type}
			id={props.id}
			value={props.value}
			onChange={props.onChange}
			onBlur={props.onBlur}
		/>
	</div>
	)

 

 

- 즉, 컴포넌트 함수는 forwardRef의 첫 번째 인수이다. 그리고 forwardRef는 리액트 컴포넌트를 반환한다.

- input은 여전히 리액트 컴포넌트지만 ref에 바인딩 될 수 있는 리액트 컴포넌트다.

- 포커싱 같은 곳에서 현실적으로 사용할 수 있다.

 

728x90