1, 리액트 contextAPI
1) 데이터를 전역으로 관리하자 contextAPI or Redux
- API 문서 : https://ko.reactjs.org/docs/context.html
- React를 하다보면 여러 컴포넌트를 거쳐서 자료를 전달해야 하거나, 동시에 같은 자료를 사용해야 하는 경우가 생깁니다.
- Context는 리액트 컴포넌트 간에 어떠한 값을 공유 할 수 있게 해주는 기능입니다.
- 주로 Context는 전역적(global)으로 필요한 값을 다룰 때 사용합니다.
2) Props로만 데이터를 전달하는 것은 한계가 있다.
- 리액트에서는 일반적으로 컴포넌트에게 데이터를 전달해 주어야 할 때 Props를 통해 전달합니다.
- 그런데, 이 컴포넌트의 형태가 복잡하다면 어떻게 될까요?
- G에서 변경된 값을 J로 가져가려면 Root를 거쳐 J로 돌아가야 합니다.
- G값을 핸들링하는 함수 또한 Root에서 선언 해야합니다.
- Props를 통해 핸들링 함수를 자식 컴포넌트(JS는 변수로 함수를 전달 가능) 로 전달해줘야 합니다.
- 이런 문제는 Context API 또는 Redux를 사용하여 공통(전역)으로 사용하는 데이터를 외부에서 편리하게 사용할 수 있습니다.
3) contextAPI 사용 방법(생성과 사용이 나눠짐)
- createContext() 훅 : ContextAPI를 생성합니다.
const 사용할이름 = createContext(초기값)
- provider(제공자: 루트가 되는 부모 컴포넌트)와 consumer(소비자: 사용하는 측, 사용하고 싶은 자식 컴포넌트)
Provider Component | 부모에서 사용 | Context의 변화를 하위 컴포넌트에 알린다. |
Consumer Component | 자식에서 사용 | 부모 Component중 가장 가까운 Provider가 전달하는 데이터를 받아서 사용한다. |
- 구현순서(2, 3은 순서 바뀌어도 무관)
1) ContextAPI를 생성한다.
2) 자식 컴포넌트에서는 Consumer를 이용해서 데이터 받기
3) 부모 컴포넌트에서는 Provider를 사용해서 value값을 제어한다.
- ContextAPI.js 생성
import { createContext } from "react";
//컨텍스트의 기본상태 지정
const ColorContext = createContext({color : 'red'}) //초기값 설정
export default ColorContext; //외부에서 사용하도록 export
- ColorComponent.js 안에서 Consumer의 사용
- Context 변화를 사용하는 React 컴포넌트입니다. 이 컴포넌트를 사용하면 함수 컴포넌트안에서 Context를 사용 할 수 있습니다.
- Context.Consumer의 자식은 함수여야합니다. (첫번째 매개변수에서 context값을 얻습니다)
- return에 화면에 렌더링할 JSX를 만듭니다.
//...
const ColorComponent = () => {
return (
<ColorContext.Consumer>
{/* ColorContext 안에 Consumer를 사용하고
JSX자리에 함수로 return을 처리하는 구문을 사용함 */}
{
(value) => (
<div style={{background: value.color}}>
ConTextAPI사용<br/>
값: {value.color}
</div>
)
}
</ColorContext.Consumer>
)
}
export default ColorComponent;
- App.js 안에서 Provider의 사용
- Context에 포함된 React 컴포넌트인 Provider는 context를 사용하는 컴포넌트들에게 context의 변화를 알리는 역할을 합니다.
- Provider 컴포넌트는 value prop을 받아서 이 값을 하위에 있는 컴포넌트에게 전달합니다.
- Provider 하위에서 context를 사용하는 모든 컴포넌트는 Provider의 value prop가 바뀔 때마다 다시 렌더링 됩니다.
//...
const App = () => {
return (
<ColorContext.Provider value={{color: 'green'}}>
<ColorComponent/>
</ColorContext.Provider>
)
}
export default App;
* 예제 - app.js, contextAPI.js, ColorComponent.js
import { Fragment, useState, handleChange } from "react";
import ColorComponent from "./component3/ColorComponent";
import ColorContext from "./contexts/ContextAPI";
const App = () => {
/*
p. 495
1. ContextAPI를 외부에 선언 createContext() 훅 사용
2. 자식 컴포넌트 consumer로 데이터를 받기
3. 부모 컴포넌트 provider로 데이터를 전달
*/
//select 태그를 만들고 usestate를 활용해서 color값을 변경
/* const [color, setColor] = useState('black'); */
const [color, setColor] = useState('black');
const handleChange = (e) => {
setColor(e.target.value);
}
return (
<ColorContext.Provider value={{ color: color }}>
{/* Provider는 사용할 root컴포넌트에 선언합니다. */}
<ColorComponent />
{/* 내 답안
<select onChange={(e) => {
setColor(e.target.value);
}}>
<option>red</option>
<option>blue</option>
<option>orange</option>
</select>
*/}
<select onChange={handleChange}>
<option value='black'>선택</option>
<option value='blue'>blue</option>
<option value='red'>red</option>
</select>
</ColorContext.Provider>
)
}
export default App;
import { createContext } from "react";
//컨텍스트의 기본 상태 지정
const ColorContext = createContext({color: 'red'});
export default ColorContext;
import { Fragment } from "react";
import ColorContext from "../contexts/ContextAPI";
const ColorComponent = () => {
return (
<ColorContext.Consumer>
{/* 사용할 곳: Consumer - 함수의 return구문에 화면을 처리할 내용을 작성함 */}
{
(value) => ( /* 소괄호, value-contextAPI에서 관리하는 초기값을 넣어줌 */
<div style={{color: value.color}}>
ContextAPI의 사용
값: {value.color}
</div>
)
}
</ColorContext.Consumer>
)
}
export default ColorComponent;
4) Provider와 consumer를 독립적으로 분리하기
- ContextAPI는 전역으로 사용할 값이기 때문에 파일을 독립적으로 분리해서 작성하도록 변경합니다.
- 하위 컴포넌트에서는 훅을 이용해서 더욱 편리하게 사용할 수 있습니다.
- useContext() 훅
- 컴포넌트에서 context API를 편하게 사용하는 훅입니다
- 리턴은 객체이고 첫번째 값은 상태값, 두번째는 값을 저장하는 setter를 가진 객체를 반환합니다.
const {state, action} = useContext(컨택스트API객체)
- 구현순서
- ContextAPI2.js 생성 (Provider재정의, Consumer를 외부로 export)
- App.js에서 Provider감싸기
- A.js 훅 으로 컨텍스트 사용하기
- ContextAPI2.js 에서는...
import { createContext, useState } from "react";
//1. 초기값 설정
const UserContext = createContext({
state : {id: 'aaa', name : 'bbb'},
action : {
setUser : () => {}
}
});
//2. Provider컴포넌트 재정의
//매개값의 이름은 반드시 children으로 구조분해할당 합니다.
//useState를 활용해서 데이터를 관리합니다.
const UserProvider = ({children}) => {
const [user, setUser] = useState({id: 'aaa', name: 'bbb'});
const value = {
state : user,
action : {setUser}
}
//Provider 반환
return (
<UserContext.Provider value={value}>{children}</UserContext.Provider>
)
}
//3. 외부에서 사용가능 하도록 consumer, provider 반환
const UserConsumer = UserContext.Consumer;
export {UserProvider, UserConsumer}
export default UserContext;
- App.js에서는
import A from "./component3/A";
import B from "./component3/B";
import { UserProvider } from "./contexts/ContextAPI2";
const App = () => {
return (
<UserProvider>
<A/>
<B/>
</UserProvider>
)
}
export default App;
- A.js 그리고 B.js에서는
import { useContext, useRef } from "react";
import UserContext, { UserConsumer } from "../contexts/ContextAPI2";
const A = () => {
//useRef훅
const input1 = useRef(null);
const input2 = useRef(null);
//useContext훅 - 을 이용해서 값 조회 or 값 변경
//Context API를 훅으로 사용
const {state, action} = useContext(UserContext);
const handleClick = () => {
action.setUser({id: input1.current.value,
name: input2.current.value});
input1.current.value = '';
input2.current.value = '';
}
return (
<div>
<h3>A컴포넌트</h3>
<input type="text" ref={input1}/>
<input type="text" ref={input2}/>
<button onClick={handleClick}>데이터변경</button>
<div>
{state.id}<br/>
{state.name}<br/>
</div>
</div>
)
}
export default A;
* 예제 - App.js, contextAPI2, A~D.js
import A from "./component3/A"
import B from "./component3/B"
import { UserProvider } from "./contexts/ContextAPI2";
const App = () => {
/*
전역 데이터 관리 ContextAPI
1. 외부 contextAPI2의 컨슈머, 프로바이더 export
2. root에서는 export된 프로바이더로 감싸줍니다.
3. 사용하는 곳에서는 useContext 훅을 사용 - 자식 컴포넌트에서는 useContext(컨텍스트명)를 이용해서 데이터를 핸들링
*/
return (
<UserProvider>
<A/>
<B/>
</UserProvider> /* return에 <UserContext.Provider value = {value}>{children}</UserContext.Provider> */
)
}
export default App;
import { createContext, useState } from "react";
//1. 초기값 설정
const UserContext = createContext({ //객체 안에 key, {}는 값
/* state: { id: 'aaa123', name: 'bbb' },
action: {
setUser: () => { }
}
*/ //확인을 하기 위한 모형일 뿐 없어도 실행 가능
})
//2. Provider 정의 - 구조분해 할당은 반드시 children으로 키를 가지고 옴
const UserProvider = ({ children }) => {
const [user, setUser] = useState({ id: 'aaa', name: 'bbb' });
const value = {
state: user,
action: { setUser } //{setUser: setUser}도 맞는데 js의 빠른 할당 구문에 의해 줄여쓰기가 가능함
}
//console.log(children);
//console.log(value);
return (
<UserContext.Provider value={value}>{children}</UserContext.Provider>
)
}
//3. Consumer, provider 반환
const UserConsumer = UserContext.Consumer;
//부모에서는 UserProvider 사용하고, 자식에서는 UserConsumer 사용
export { UserProvider, UserConsumer }; //여러개를 반환할 때는 default말고 {}에 나열
//4. 기본 export
export default UserContext;
import { useContext, useRef } from "react";
import UserContext from "../contexts/ContextAPI2";
const A = () => {
//초기값을 구조 분해 할당
const { state, action } = useContext(UserContext);
//useRef
const input1 = useRef(null);
const input2 = useRef(null);
const handleClick = () => {
//console.log(input1.current.value); //사용자의 입력값
//console.log(input2.current.value);
//contextAPI의 action
action.setUser({
id: input1.current.value,
name: input2.current.value
});
}
return (
/* 2nd - useContext 훅을 이용해서 처리 */
<div>
<h3>A 컴포넌트</h3>
컨텍스트 안에 값: {state.id}<br />
컨텍스트 안에 값: {state.name}<br />
<div>
<input type="text" ref={input1} />
<input type="text" ref={input2} />
<button onClick={handleClick}>컨텍스트 데이터 변경</button>
</div>
</div>
/* 1st
<UserConsumer>
{
(value) => (
<div>
<h3>A 컴포넌트</h3>
컨텍스트 안에 값: {value.state.id}<br/>
컨텍스트 안에 값: {value.state.name}<br/>
</div>
)
}
</UserConsumer>
*/
)
}
export default A;
import { useContext } from "react";
import UserContext from "../contexts/ContextAPI2";
import C from "./C";
import D from "./D";
const B = () => {
const { state, action } = useContext(UserContext);
return (
<>
<h3>B 컴포넌트</h3>
컨텍스트 안의 값: {state.id} <br />
컨텍스트 안의 값: {state.name} <br />
<C />
<D />
</>
)
}
export default B;
import { useContext } from "react";
import UserContext from "../contexts/ContextAPI2";
const C = () => {
const { state, action } = useContext(UserContext);
return (
<>
<h3>C 컴포넌트</h3>
컨텍스트 안의 값: {state.id} <br />
컨텍스트 안의 값: {state.name} <br />
</>
)
}
export default C;
import { useContext, useRef } from "react";
import UserContext from "../contexts/ContextAPI2";
const D = () => {
const { state, action } = useContext(UserContext);
const input1 = useRef(null);
const input2 = useRef(null);
const handleClick = () => {
//console.log(input1.current.value); //사용자의 입력값
//console.log(input2.current.value);
//contextAPI의 action
action.setUser({
id: input1.current.value,
name: input2.current.value
});
}
return (
<>
<h3>D 컴포넌트</h3>
컨텍스트 안에 값: {state.id}<br />
컨텍스트 안에 값: {state.name}<br />
<div>
<input type="text" ref={input1} />
<input type="text" ref={input2} />
<button onClick={handleClick}>컨텍스트 데이터 변경</button>
</div>
</>
)
}
export default D;
2. firebase에 react 배포하기
1) 배포의 단계
개발(develop) - 빌드(build) - 배포(deploy)
- 개발 : 만드는 단계
- 빌드 : 어플리케이션 가동의 필요한 것들을 통합하고, 경량화 시키는 단계 (배포를 위한 준비과정)
- 배포 : 서버에 반영을 하는 것
- 웹앱을 무료로 배포하는 다양한 방법이 존재합니다.
1]깃허브페이지
2] 구글 firebase
3] 기타 등등
- 이번에는 firebase를 이용해서 배포를 진행하도록 합니다.
2) 리액트 빌드하기
1] 프로젝트 최상위 루트에서 실행하세요.
npm run build
2] 실행하면 build폴더가 생성됩니다.
3] build폴더 안에는 개발 단계에서 복잡한 코드를 경량화해서 index.html을 생성해줍니다.
4] 바로 실행하게 되면 서버가 아니라서 정상적으로 실행이 안 될텐데요. 아래 명령어로 1회용 서버로 실행 시켜보세요.
npx serve -s build
5] http://localhost:3000으로 들어가보면 빌드된 결과물이 나옵니다.
3) 파이어 베이스 배포하기
- 파이어베이스는 2011년 파이어베이스사가 개발하고 2014년 구글에 인수된 모바일 및 웹 애플리케이션 개발 플랫폼이다. 위키백과
1] firebase에 가입하고 콘솔로 이동합니다.
2] 프로젝트를 생성해 주세요.
3] hosting으로 들어갑니다.
4] 시작하기를 클릭해서 단계 별로 실행합니다. (firebase문서에 상세하게 나와있습니다^^) - 호스팅에서 시작하기 누르기
5] 컴퓨터에는 node.js가 설치되어야 합니다.
- vs코드에서 아래 명령문을 실행합니다.
- 프로젝트에 최상위 경로에서 진행해 주세요. (최상위 경로)
- 파이어베이스 설치
npm install -g firebase-tools
- 파이어베이스 로그인
npx firebase login
- 파이어베이스 설정시작
npx firebase init
- firebase 시작할거야? y
- 파이어 베이스에서 시작할 기능을 스페이스로 선택하세요.
- hosting을 선택합니다. (space선택 -> 엔터)
- 너의 기본 경로를 어디로 사용 할거에요? build
- 리액트는 빌드시 폴더가 build로 생성되기 때문에 public폴더를 build로 잡아주세요 (디폴트 public)
- 싱글페이지 앱으로 구성할거에요? yes
- 깃허브에서 자동으로 배포하게 만들거에요? no
- index파일이 있는데 덮어쓸까요? no
- yes를 선택하면 build했던 내용이 기본파일로 덮어집니다.
- 마지막 질문: 덮어쓰면 기본으로 제공되는 화면이 나옵니다. 절대 덮지 말 것!
6] 파이어 베이스에 배포
npx firebase deploy
7] hosting url에서 확인하면 됩니다.
8] 이후에 배포는? - 업데이트 되는 내용들을 덮어서 배포해줌(빌드하고 올리고, 빌드하고 올리고)
- npm run build (리액트 빌드)
- npx firebase deploy (파이어베이스에 배포)만 하면됩니다.
'TIL > React' 카테고리의 다른 글
day71-react (0) | 2023.01.20 |
---|---|
day70-react (0) | 2023.01.19 |
day69-react (0) | 2023.01.18 |
day68-react (0) | 2023.01.18 |
day67-react (0) | 2023.01.17 |