context api
context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다.
일반적인 React 데이터는 위에서 아래로 즉 부모에서 자식으로 props를 통해 전달된다.
하지만 여러 컴포넌트에게 전달해줘야한다면 props drilling과 같은 컴포넌트를 지나 또 props를 넘겨줘야 한다.
컴포넌트가 한 두 개 정도이면 크게 불편함도 없지만, 만약 컴포넌트가 3~4개 혹은 그 이상일 경우에는 props를 넘겨주는 것만으로도 굉장히 번거로워 질 수 있다.
하지만 context를 이용하면 많은 컴포넌트가 공통으로 state를 공유 할 수 있게 된다.
사용법
context는 리액트에서 제공하는 createContext를 사용해서 생성할 수 있다.
import { createContex } from 'react';
export const GlobalContext = createContext({
name: "",
setName: (_) => {}
})
context 데이터를 사용할 변수에 createContex 함수의 인자값으로 관리할 state 들을 객체 형태로 담아준다.
state를 설정했으니 state 값을 변경할 수 있는 set함수도 함께 설정할 수 있다.
위와 같이 만들어도 아직 state의 값이 만들어진 것은 아니다.
useState를 이용해 설정한 state 값들을 만들어줘야 한다.
function MyApp({ Component, pageProps }) {
const [name, setName] = useState("anyName");
설정한 state 값들은 useState로 생성하면 된다.
그럼 이제 하위 컴포넌트로 뿌려주기 위한 작업을 해주면 된다.
app.js 또는 app.tsx가 페이지를 그려내는 부분이기 때문에 return 해주는 곳에 전체 페이지들을 context로 감싸준다.
return (
<GlobalContext.Provider value={{
name, setName
}}>
<ApolloProvider client={client}>
<Layout>
<Global styles={globalStyles} />
<Component {...pageProps} />
</Layout>
</ApolloProvider>
</GlobalContext.Provider>
위 코드와 같이 GlobalContext로 감싸줄때 Provider기능을 사용할 수 있다.
Provider기능은 value속성으로 전체 페이지에 state 값을 넣어줄 수 있다.
이제부터는 모든 컴포넌트에서 Provider로 전달된 state의 값들을 가지게 된다.
import {useContext} from "react"
import {GlobalContext} from "/.app"
export default function ContextTestPage() {
const {name, setName} = useContext(GlobalContext);
return(
<div>이름: {name}</div> // 이름: anyname
)
}
이제 컴포넌트에서는 위와 같이 props를 통해 state를 넘겨받지 않아도 공통스테이트를 관리하는 컴포넌트에서 바로 불러와서 사용할 수 있게 된다.
하지만 context를 사용하면 컴포넌트의 재사용성이 떨어지므로 너무 남발하지 않는게 좋다.
위에서 설명한 context-api에는 한가지 단점이 있다.
Provider로 감싸고 있는 부분이 업데이트가 되지 않은 state에도 리렌더가 일어나게 된다.
하지만 recoil은 이와 같은 context의 단점을 보완하여 나왔다.
recoil은 업데이트된 state 부분만 리렌더를 실행하게 되는데, 하지만 같은 state를 가지고 있다면 그 부분 또한 리렌더가 된다.
이러한 부분 때문에 context 보다 불필요한 렌더링이 줄어들게 된다.
사용법
사용법 또한 context에 비해 조금더 간단하다.
먼저 터미널에 yarn add recoil 을 입력한다.
npm을 사용중이라면 install을 해주면 된다.
//app.tsx 파일
import {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
} from 'recoil';
function App() {
return (
<RecoilRoot>
// RecoilRoot로 모든 컴포넌트를 묶어줌
<Component />
</RecoilRoot>
);
}
위와 같이 app 파일에 세팅을 해주면 준비는 끝난다.
// Atom
import {atom} from 'recoil'
const textState = atom({
key: 'textState', // state의 이름
default: '', //초기값
});
recoil에서는 state를 atom으로 참조를 하게 되고 위에서 말한 같은 부분을 리렌더 해준다는 것은 같은 atom을 참조하고 있는 state를 말하는 것이다.
즉 atom을 참조하고 있는 state를 가지고 있는 컴포넌트는 모두 리렌더링이 일어나게 되는 것이다.
// TextInput 컴포넌트
function TextInput() {
const [text, setText] = useRecoilState(textState);
const onChange = (event) => {
setText(event.target.value);
};
return (
<div>
<input type="text" value={text} onChange={onChange} />
<br />
Echo: {text}
</div>
);
}
atom을 불러온 컴포넌트에서 사용하는 방법 또한 간단하다.
recoil은 useState를 사용하지 않고, 위와 같이 useRecoilState를 사용하게 된다.
그 부분 이외에는 useState와 다른 부분은 없다.
이제는 props를 사용하지 않고 같은 state를 공유할 수 있게 된다.
Redux
리덕스(redux)는 자바스크립트의 상태관리 라이브러리이다.
리덕스의 기본 개념
동일한 데이터는 항상 같은 곳에서 가지고 온다.
context-api와 마찬가지로 스토어라는 하나의 데이터 공간이 있다.
리액트에서는 setState를 활용해 상태 변경을 하는데 리덕스에서는 액션이라는 객체를 통해 상태를 변경한다.
리덕스에서는 상태변경을 할 때 순수 함수로만 가능하다.
리듀서와 연관되는 개념이다.
Action
액션(Action)은 앱에서 스토어에 운반할 데이터를 말하고 자바스크립의 객체 형식으로 되어있다.
{
type: 'ACTION_CHANGE_USER', // 필수
payload: { // 옵션
name: '철수',
age: 13
}
}
Reducer
액션을 스토어에 바로 전달하는 것이 아니다.
액션을 리듀서에 전달해야한다.
리듀서가 주문을 보고 스토어의 상태를 업데이트 하는 것이다.
액션을 리듀어세 전달하기 위해서는 dispatch() 메소드를 사용해야 한다.
리덕스의 데이터 흐름은 단방향이다.
그렇기에 아래와 같은 흐름을 가진다.
액션이 dispatch()메소드에 전달된다.
dipatch(Action)를 통해 Reducer를 호출한다.
Reducer는 새로운 store를 생성한다.
리덕스는 추가적인 라이브러리 설치로 인해 프로젝트가 무거워진다.
또한 사용방법도 리코일에 비해 복잡한 부분이 있다.
출처
Mobx 또한 상태 관리 라이브러리들 중 하나이다.
Mobx의 특징
리액트에 종속적인 라이브러리가 아니다.
리덕스와 다르게 스토어에 제한이 없다.
리액트에 액션 선언과 같은 작업들은 데코레이터로 대체한다.
observable을 기본적으로 사용하고 있다.
Mobx는 필요한 경우에만 state를 변경
타입스크립트 기반으로 만들어졌다.
Mobx를 사용하는 이유
객체지향적 이다.
단일스토어를 강제하지 않는다.
불변성 유지가 중요하지 않다.
리덕스 보다 사용하기 편하다.
Swr
SWR은 데이터를 가져오는 리액트의 훅스이다.
SWR은 먼저 개시로부터 데이터를 반환한 후 fetch 요청을 하고 최종적으로 데이터를 가져온다.
SWR을 사용하면 컴포넌트는 지속적이며 자동으로 데이터 업데이트 스트림을 받게 된다.
import useSWR from 'swr'
function Profile() {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
위 예시에서 useSWR hook은 문자열로 된 키와 함수를 받는다.
키는 고유한 식별자 이다.
그리고 함수는 데이터를 반환하는 어떠한 비동기 함수도 될 수 있다.
훅은 요청의 상태에 기반한 데이터와 에러 두 개의 값을 반환한다.
SWR의 기능
SWR은 단 한줄의 코드로 프로젝트 내에 데이터를 가져오는 로직을 단순화 할 수 있다.
빠르고 가볍고 재상용성이 좋다.
실시간으로 업데이트를 받을 수 있다.
출처: 링크텍스트