useReducer 사용법
#1 지시사항
- App.js에서 initial 상수에 초기값을 완성해주세요.
- top: apple
- middle: banana
- bottom: coconut
- 다음 사항에 맞추어 **reducer**를 작성해주세요. 서로 바꿀 수 있는 기능을 제공하도록 합니다.
- top-middle-change: top ↔ middle
- middle-bottom-change: middle ↔ bottom
- top-bottom-change: top ↔ bottom
- top-update: 이전 ↔ action.payload
- middle-update: 이전 ↔ action.payload
- bottom-update: 이전 ↔ action.payload
- **useReducer**를 사용해 state, **dispatch**를 **value**에 넣어서 **Provider**에 전달해주세요.
- B.jsx에서 **Context**로 부터 **dispatch**를 받아서 **button**에 action 객체를 전달해주세요.
- **payload**에는 **useRef**로 **input**에 입력된 텍스트 값을 전달합니다.
// App.jsx
import React, { createContext, useReducer } from 'react';
import ContainerA from './components/A';
import './App.css';
export const MyContext = createContext(null);
/*
다음 초기값을 완성해주세요.
*/
const initial = {
top: 'apple',
middle: 'banana',
bottom: 'coconut',
};
/*
상태 변경 설명서라 할 수 있는 reducer를 지시사항에 맞게 작성해주세요.
*/
function reducer(state, action) {
switch (action.type) {
case 'top-middle-change':
return {
...state,
top: state.middle,
middle: state.top,
};
case 'middle-bottom-change':
return {
...state,
middle: state.bottom,
bottom: state.middle,
};
case 'top-bottom-change':
return {
...state,
top: state.bottom,
bottom: state.top,
};
case 'top-update':
return {
...state,
top: action.payload,
};
case 'middle-update':
return {
...state,
middle: action.payload,
};
case 'bottom-update':
return {
...state,
bottom: action.payload,
};
default:
throw new Error();
}
}
export default function App() {
// useReducer를 사용해 state와 dispatch를 value 넣어서 전달해주세요.
//데이터를 보내주기위한 작업. state는 상태값 데이터값 이라고생각하면되고. useReducer로 보냄.
// initial이 위쪽에 정해진 데이터 저장소
// reducer은 조종하는곳. 컨트롤룸 느낌.
// dispatch 는 갱신하기 위한 조이스틱 느낌
const [state, dispatch] = useReducer(reducer, initial);
const value = {
state,
dispatch,
};
return (
<div className="layout">
<MyContext.Provider value={value}>
<ContainerA />
</MyContext.Provider>
</div>
);
}
B.jsx
// B.jsx
import ContainerC from './C';
import ContainerD from './D';
import ContainerE from './E';
import { useContext, useRef } from 'react';
import { MyContext } from '../App';
export default function ContainerB() {
// Context로 부터 dispatch를 받습니다.
const { state, dispatch } = useContext(MyContext);
const inputRef = useRef();
return (
<div>
<div className="container b">
<div className="title">Component B</div>
<div className="content">
<ContainerC />
<ContainerD />
<ContainerE />
<div className="button-group">
<button
onClick={() => {
// 올바른 액션 타입을 지정해주세요.
dispatch({ type: 'top-middle-change' });
}}
>
Top Middle Change
</button>
<button
onClick={() => {
// 올바른 액션 타입을 지정해주세요.
dispatch({ type: 'middle-bottom-change' });
}}
>
Middle Bottom Change
</button>
<button
onClick={() => {
// 올바른 액션 타입을 지정해주세요.
dispatch({ type: 'top-bottom-change' });
}}
>
Top Bottom Change
</button>
</div>
<div className="button-group">
<input type="text" data-testid="input" ref={inputRef} />
<button
onClick={() => {
// 올바른 액션 타입과 페이로드를 전달해주세요.
dispatch({
type: 'top-update',
payload: inputRef.current.value,
});
}}
>
Top Update
</button>
<button
onClick={() => {
// 올바른 액션 타입과 페이로드를 전달해주세요.
dispatch({
type: 'middle-update',
payload: inputRef.current.value,
});
}}
>
Middle Update
</button>
<button
onClick={() => {
// 올바른 액션 타입과 페이로드를 전달해주세요.
dispatch({
type: 'bottom-update',
payload: inputRef.current.value,
});
}}
>
Bottom Update
</button>
</div>
</div>
</div>
</div>
);
}
useRef() 를 이용한 인풋값을
inputRef.current.value 를 payload로 보내서 등록한다는 개념.
payload는 데이저 저장소의 느낌으로 생각하면된다. 갱신?느낌
깃허브로 Vercel 연결하기
Vercel의 특징 중 하나는, GitHub와 같은 코드베이스(저장소)를 연결하여, 즉시 빌드를 실행하고, 배포까지 원클릭으로 할 수 있다는 점이 특징이다. 실제로 배포는 Vercel 서비스 내에서 이루어진다.
그럼 시작해보자.
우선 vercel에 로그인을 한다.(vercel 로그인 바로가기) 나는 github으로 로그인 했다.
로그인을 하면 아래와 같이 Import Git Repository 화면을 볼 수 있을 것이다. Add GitHub Org or Account 를 클릭해서 내 GitHub 계정을 연결해준다.
내 계정과 연동이 끝나면 내 레포지토리 목록이 뜰 것이다. 그럼 배포하고 싶은 레포지토리에 Import를 클릭한다.
나는 다음 메인페이지를 카피해본 프로젝트를 배포하려고 한다. PROJECT NAME은 원하는 대로 설정하고, FRAMEWORK PRESET은 나는 create react app을 사용해서 만든 프로젝트이기 때문에 저것을 선택했다.
그리고 ROOT DIRECTORY는 src파일이 있는 바로 상위 폴더를 선택해준다.
그 다음 Build and Output Settings에서 OVERRIDE를 아무것도 열지않고 기본값이 실행되도록 해서 Deploy를 시작했다.
여기서 나는 에러를 만났다.
process.env.CI = true라서 안된다고 하는 것 같다.
vercel의 문서는 아니지만 비슷한 배포 사이트인 netlify의 공식문서를 살펴보면 CI='' npm run build라고 해주면 된다고 한다.
그럼 다시 BUILD COMMAND로 가서 CI='' npm run build라고 작성해주자
수정해준 결과!!
인풋 값 데이터를 보내서 유저를 추가 한 후에 데이터를 다시받기.
아래는 내가 생각해서 만든코드. useState를 사용해서 하는데.
이게 효율적일까? 아니면 그냥 함수로 만들어서 하는게 나을까라는 생각이듬.
import React, { useState, useEffect } from "react";
import * as authAPI from "../service/auth";
import styled from "styled-components";
import RegisterForm from "./RegisterForm"
import UserDetail from "./UserDetail";
// RegisterForm을 이용해 유저 정보를 가져와 화면을 업데이트하세요.
const WrappedUserDetail = styled(UserDetail)`
& + & {
margin-top: 12px;
}
`;
export default function BitcoinApp() {
const [users, setUsers] = useState(undefined);
const [formData,setNewData] = useState()
useEffect(() => {
authAPI.getUsers().then((data) => {
console.log(data);
setUsers(data);
});
}, []);
useEffect(()=>{
if(formData){ //registerUser 함수는 데이터를 추가해주는 따로 만들어둔 함수이다.
authAPI.registerUser(formData).then(authAPI.getUsers).then((data)=>{
setUsers(data)
}).catch(console.error)
}
},[formData]);
if (!users) {
return <div>유저 정보를 불러오는 중입니다...</div>;
}
return (
<div>
<RegisterForm onSubmit={setNewData}/>
{users.map((user) => (
<WrappedUserDetail {...user} />
))}
</div>
);
}
강의정답 코드. 이게좀더 효율적일지도?
import React, { useState, useEffect } from "react";
import * as authAPI from "../service/auth";
import styled from "styled-components";
import RegisterForm from "./RegisterForm"
import UserDetail from "./UserDetail";
// RegisterForm을 이용해 유저 정보를 가져와 화면을 업데이트하세요.
const WrappedUserDetail = styled(UserDetail)`
& + & {
margin-top: 12px;
}
`;
export default function BitcoinApp() {
const [users, setUsers] = useState(undefined);
useEffect(() => {
authAPI.getUsers().then((data) => {
console.log(data);
setUsers(data);
});
}, []);
const handleSubmit = (formData) =>{ // then에 안에서는 () 사용은 생각해봐야한다.
authAPI.registerUser(formData)
.then(authAPI.getUsers)
.then(data => setUsers(data))
.catch(console.error)
}
if (!users) {
return <div>유저 정보를 불러오는 중입니다...</div>;
}
return (
<div>
<RegisterForm onSubmit={handleSubmit}/>
{users.map((user) => (
<WrappedUserDetail {...user} />
))}
</div>
);
}
괄호가 되면 바로 실행해서 콜백으로 결과값을 받고 괄호가 없다면 참조해서 실행을한다? 변수에 저장(참조?)하는게 가능하기도하다.
내생각에는 then()의 괄호 안에 있냐 없냐의 차이 같기도?
authAPI.getUsers()와 authAPI.getUsers의 주된 차이는 함수를 호출하는 것과 호출하지 않는 것 사이의 차이입니다.
- authAPI.getUsers(): 이것은 함수를 호출하는 것을 나타냅니다. 괄호가 있어서 함수가 즉시 실행됩니다. 함수가 호출되면 해당 함수의 반환값이 반환됩니다.
- authAPI.getUsers: 이것은 함수를 참조하는 것을 나타냅니다. 괄호가 없으므로 함수가 즉시 실행되지 않고, 대신에 함수에 대한 참조가 반환됩니다. 이를 "함수를 호출하지 않고 참조만 하는 것"이라고 생각할 수 있습니다. 나중에 코드에서 이 참조를 사용하여 함수를 호출할 수 있습니다.
여러개의 인풋을 하나의 핸들링함수로 동적으로 사용하기.

어트리뷰트를 이용한 하나의 함수로 여러개의 인풋 관리해보기
연습이 필요한것같다.
import React,{useState} from 'react';
function App() {
const [person,setPerson] = useState({
name: "김민수",
school: "엘리스대학교"
})
const handleChaing = (e) =>{
const {name,value} = e.target //value 까지 넣으면 수정이안된다.
const newValue = {...person}
newValue[name] = value; //여기서의 name은 name와 value다. name의 어트리뷰트 속성이다!
setPerson(newValue)
}
const click = () =>{
alert(`${person.name}님은 ${person.school}에 재학중입니다.`)
}
return (
<div className="App">
<input name="name" value={person.name} type="text" onChange={handleChaing} />
<input name="school" value={person.school} type="text" onChange={handleChaing} />
<button onClick={click}>클릭</button>
</div>
);
}
export default App;
사용하면서 실수한건 e.target.value 이걸로 해서 수정이안된다.
value를빼야 동적으로 name 속성의 벨류값을 가져오는것으로 생각된다.
그리고 이걸로 이용해서 서밋했을때 set에 데이터를 넣어서. 데이터를 한번에 보내는게 가능하지않을까?
#엘리스트랙 #엘리스트랙후기 #리액트네이티브강좌 #온라인코딩부트캠프 #온라인코딩학원 #프론트엔드학원 #개발자국비지원 #개발자부트캠프 #국비지원부트캠프 #프론트엔드국비지원 #React #Styledcomponent #React Router Dom #Redux #Typescript #Javascript
'공부용' 카테고리의 다른 글
[수업일지]엘리스 트랙 14주차 블로그 챌린지. 로대쉬?로다쉬 라이브러리 (0) | 2023.12.21 |
---|---|
[수업일지]엘리스 트랙 13주차 블로그 챌린지. (1) | 2023.12.09 |
지역변수와 전역변수의 차이와 사용이유 (0) | 2023.11.17 |
엘리스트랙 sw과정 - 1차 프로젝트 (0) | 2023.11.01 |
프론트엔드 솔리드 패턴 객체지향 프로그래밍. (0) | 2023.10.15 |