상위 컴포넌트 => 하위 컴포넌트 데이터 전달할 때 속성값 사용하지만 하위 컴포넌트가 많을 경우 속성값을 사용하면 불편해서 "context"라는 것을 사용함
import logo from './logo.svg';
import './App.css';
import React,{createContext, useState} from 'react';
const UserContext = createContext("unknown");
export default function App(){
const [name, setName] = useState("mike");
return(
<div>
<UserContext.Provider value={name}>
<div>상단메뉴</div>
<Profile/>
<div>하단메뉴</div>
<input type="text" value={name} onChange={e=>setName(e.target.value)}/>
</UserContext.Provider>
</div>
);
}
const Profile = React.memo(function (){
return (
<div>
<Greeting/>
{/* ... */}
</div>
);
});
function Greeting(){
return (
<UserContext.Consumer>
{username => <p>{`${username}님 안녕하세요.`}</p>}
</UserContext.Consumer>
);
}
위의 function Greeting(){}을 useContext훅을 사용해서 다음과 같이 표현
function Greeting(){
const username = useContext(UserContext);
return <p>{`${username}님 안녕하세요.`}</p>
}
ref속성값을 사용하면 자식요소에 접근가능
상단에 useRef import
import logo from './logo.svg';
import './App.css';
import React,{useRef,useEffect} from 'react';
export default function App(){
const inputRef = useRef();
useEffect(()=>{
inputRef.current.focus();
}, []);
return(
<div>
<input type="text" ref={inputRef}/>
<button>저장</button>
</div>
);
}
forwordRef함수
문자를 입력할 때 , 컴포넌트가 계속 렌더링 되는데 새로운 함수가 렌더링 되면서 inital text가 계속 ref속성값으로 들어가서 키보드 값이 안먹히는 것임 => useCallback()훅의 메모자이션 기능으로 해결 가능
접근하는 돔의 요소가 많을 경우
import logo from './logo.svg';
import './App.css';
import React,{useContext, crateContext, useRef,useState,useEffect} from 'react';
export default function App(){
const boxListRef = useRef({});
function onClick(){
let maxRight = 0;
let maxId = '';
for(const box of BOX_LIST){
const ref = boxListRef.current[box.id];
if(ref){
const rect = ref.getBoundingClientRect();
if(maxRight < rect.right){
maxRight = rect.right;
maxId = box.id;
}
}
}
alert(`오른쪽 끝 요소는 ${maxId}입니다.`);
}
return(
<div>
<div
style={{
display: 'flex',
flexWrap: 'wrap',
width: '100vw',
height: '100%',
}}
>
{BOX_LIST.map(item => (
<div
key={item.id}
ref={ref=>{boxListRef.current[item.id]=ref}}
style={{
flex:'0 0 auto',
width: item.width,
height: 100,
backgroundColor: 'yellow',
border: 'solid 1px red',
}}
>{`box_${item.id}`}</div>
))}
</div>
<button onClick={onClick}>오른쪽 끝 요소는?</button>
</div>
);
}
const BOX_LIST = [
{ id: 1, width: 70 },
{ id: 2, width: 100 },
{ id: 3, width: 20 },
{ id: 4, width: 30 },
{ id: 5, width: 40 },
{ id: 6, width: 80 },
{ id: 7, width: 90 },
];
리액트 내장 훅
useRef: 이전 값을 기억하고 싶을 때
useMemo
: const value = useMemo(()=>runExpensiveJob(v1,v2),[v1,v2]); 두번째 배열은 의존성 배열, 의존성 배열이 변경될때만 함수가 실행됌
useCallback: 불필요한 렌더링을 막아줌, 의존성 배열로 관리
useReducer
: 상태값을 변경할 때 사용
: const [state, dispatch] = useReducer(reducer,INITIAL_STATE);
: 현재 상태값과 액션이 입력이 되고 액션을 보고 상태값을 어떻게 할지 결정함
: dispatch()로 객체 형식으로 부르면 useReducer에서 state를 변경함
useImparativeHandle: ref속성값을 받아서 첫번재 매개변수로 넣음 두번째 매개변수로 함수를 입력
useLayoutEffect: useEffect와 비슷하나, 부수효과 함수에서 연산을 많이 하면 브라우저가 먹통이 될 수도 있으니 주의. 조건에 따라 렌더링하고 싶을 때 사용. 실제 돔에 반영된 후에 함수가 실행됌
useDebugValue: 커스텀 훅을 만들어 사용할 때, 리액트 개발자 도구에 좀 더 풍부한 정보를 제공해줌. 디버깅할 때 편리함. -> 리액트 개발자 도구에서 확인 가능
컴포넌트 파일 작성법
함수의 PropType 속성의 타입값을 입력정보 작성가능
명명된 매개변수 사용하는게 좋음
MyComponent.propTypes = {};
export default function MyComponent(prop1, prop2){}
큰 객체를 정의할 때는 컴포넌트 외부에서 사용하는게 좋음(성능상)
훅끼리 모아서 관리보다 연관된 코드끼리 모아서 관리하는 것이 편함
prop-types 패키지로 속성값 타입 정보 입력하는 방법
: 타입이 왜 중요할까? 정적타입언어를 사용하는 것이 좋음.
prop-types 패키지 사용하는 이유
: 패키지로 사전에 타입오류를 잡을 수 있고, 타입정의 자체가 중요한 문서가 될 수 있음.
propTypes.number / .oneOf([]) / .func() / .instanceOf() / .string / .objectOf / .isRequired(필수로사용해야하는것)
${name}님 안녕하세요.
: '권한이 없습니다.'}: 삼항연산자변수가 number,string일 경우, 확실히 boolean타입으로 바꿔줘야함. 변수 앞에 !! 두개 붙여주면 됌.
function GreetingA({isLogin, name}){
if(isLogin){
return <p>{`${name}님 안녕하세요.`}</p>
} else {
return <p>권한이 없습니다.</p>
}
}
function GreetingB({isLogin,name}){
return <p>{isLogin ? `${name}님 안녕하세요.` : '권한이 없습니다.'}</p>
}
function GreetingC({isEvent, isLogin, name, cash }){
return (
<div>
저희 사이트에 방문해주셔서 감사합니다.
{isEvent && (
<div>
<p>오늘 이벤트 놓치지 마세요.</p>
<button onClick={onClickEvent}>이벤트 참여하기</button>
</div>
)}
{!isEvent && isLogin && cash <= 10000 && (
<div>
<p>{name}님 안녕하세요.</p>
<p>현재 보유하신 금액은 {cash}원 입니다.</p>
</div>
)}
</div>
);
}
component폴더: 속성값이나 상태값이 없는 파일, 재사용성이 높은 파일들
container폴더: 재사용성이 없는 파일들
App.js에서는 여러페이지를 라우팅하는 걸로(컴포넌트를 부르면서)
의존성 배열을 관리하는 방법
: 끝에 빈 배열을 넣고, 매개변수 넣는것도 조심
의존성 배열에 필요한 매개변수를 넣지 않았을 때 발생하는 문제점
: 오래된 변수를 사용하게 되겠음
부수효과 안에 있는 함수를 밖에서 사용하고 싶을 땐?
: 함수를 밖으로 꺼내고 의존성 배열에 함수를 입력해야 함.
: 부수효과 함수내에서 함수의 실행시점을 조절할 수 있음
setInterval(), clearInterval()
성능을 최적화하는 방법1(렌더링)
*component(Data) -> 가상돔과 비교 -> 실제 돔에 반영
React.memo는 속성값 비교함수를 통해서 컴포넌트 렌더링 과정을 생략할 수 있음
=> App.js
import './App.css';
import React,{ useState } from 'react';
import MyComponent from './MyComponents'
export default function App(){
const [value1, setValue1] = useState(0);
const [value2, setValue2] = useState(0);
return(
<div>
<p> 실전 리액트 </p>
<button onClick = { () => setValue1(value1+1)}> value1 증가 </button>
<button onClick = { () => setValue2(value2+1)}> value2 증가 </button>
<MyComponent value1={value1} value2={value2}/>
</div>
);
}
=> MyComponents.js
import React,{ useState } from 'react';
function MyComponents({ value1, value2 }) {
return (
<div>
<p>{`value1: ${value1}`}</p>
<p>{`value2: ${value2}`}</p>
</div>
);
}
function isEqual(prevProps, nextProps) {
return prevProps.value1 == nextProps.value1;
}
export default React.memo(MyComponents, isEqual);
import './App.css';
import React,{ useState, useEffect } from 'react';
export default function App(){
const [flag, setFlag] = useState(true);
useEffect(()=>{
setTimeout(()=>setFlag(prev => !prev), 1000);
})
if(flag){
return(
<div>
<p>사과</p>
<p>바나나</p>
</div>
);
}
else{
return(
<div>
<p>사과</p>
<p>바나나</p>
<p>파인애플</p>
</div>
);
}
}
이렇게 하면, 어떤값이 변경됬는지 알 수 없는데, 태그에 key값을 추가하면 리액트는 같은 Key를 갖는 요소끼리만 비교를 한다.
key속성값은 id와 비슷하 느낌.