github 처음설치
github에서 새로운 레포지토리 생성(readme는 체크하지 말자! 추후 에러발생 가능)
git init
.gitignore 파일생성(파일내용: node_modules)
git add. (저장소 올리기) // git rm --cached ~~ 저장소 올린것 다시 비우기
git status (저장소 상태보기)
git commit -m "쓸말" (로컬 저장하기)
git remote add origin master
변경된 내용 git에 올리기
1. git add .
2. git status에서 확인
3. git commit -m "메시지"
4. git push origin master
클로닝 하는 방법
git clone https://github.com/react-boilerplate/react-boilerplate.git
npm run setup
npm start
설치 프로그램: postman, nodemon(서버 접속시 자동 새로고침 기능을 위함)
npm install nodemon --save-dev --> package.json에 script 추가 --> 해당 용어로 서버 실행시킬 수 있음(start 대신)
비밀번호처럼 예민한 정보는 .gitignore에 옮겨야 함
환경변수 process.env.NODE_ENV
--> Local환경에서는development(config/dev.js)
--> Deploy(배포) 한 후에서는 production(config/prod.js)
Bcrypt 데이터 암호화
npm install bcrypt --save
로그인 토큰 생성을 위해서 JSONWEBTOKEN 라이브러리를 다운로드
npm install jsonwebtoken --save
npm install cookie-parser --save
프론트 폴더 구성한 다음
npx create-react-app .
(global로 받지 않고 local로 받아서 항상 최신버전 사용 가능)
폴더명 및 기능
_actions, _reducer: redux를 위한 폴더
components/view 페이지를 넣는 폴더
components/view/Section 해당 페이지 관련 css파일, 컴포넌트 삽입
app.js 라우팅 관련 일 처리.
config.js 환경 변수같은 것들 정하는 곳
hoc: higher Order Component의 약자(ex. auth권한을 통해 특정 컴포넌트 조회가능시 등 검토)
utils: 여러군데에서 쓰일 수 있는 것들을 이곳에 넣어둬서 어디서든 쓸수 있게 해줌
npm install http-proxy-middleware --save
백앤드와 프론트 서버를 동시에 npm start시키는 방법: concurrently
npm install concurrently --save
※ 상위폴더에서 실행시켜야 함!!
npm install multer --save (동영상 업로드시)
npm install fluent-ffmpeg(비디오 썸네일 생성) - 사전에 ffmpeg 사이트에서 설치필요
필요기능
※ 코딩시 나는 에러 정리할 필요 있다.
※ 레이아웃 분기
layout.js const Layout = ({ children }) => (<div>{children}</div>);
index.js const Index = () => (<Layout>{...}</Layout>);
※ Form에 대한 라이브러리 사용 필요! --> 방법 구상해 봐야 할 것
※ 리랜더링시: 함수내 다 실행 되지만 리턴부분 중에서 바뀐 부분만 다시그린다.(값 입력시 등)
--> callback으로 다른값 안바뀌게 하기도
※ 객체는 { }로 감싸는 게 맞고요. ()는 그냥 모든 값을 감쌀 수 있습니다. 다만 수학에서처럼 ()로 감싼 것은 연산할 때 우선순위가 부여됩니다.
{ }로 객체를 감쌀 때 주의할 점은 화살표 함수 사용 시입니다.
const a = () => {} 이렇게 되면 마지막 {}가 객체인지 함수의 몸통인지 헷갈립니다. a = () => {} 이런 경우 함수의 몸통이고 () => ({}) 이런 경우 {} 객체를 return하는 겁니다.
※ 실제 사이트에서는 회원가입 시 약관동의를 읽고 약관동의를 체크하는 방식인데 그런 약관동의에 대한 글들은 따로 모듈 같은게 있나요? 아님 제가 따로 작성을 해야되는건가요?
A: 모듈은 따로 쓰지는 않고 직접 작성을 많이 합니다. 다만 변경된 약관들도 모두 저장하고 있어야 해서 따로 파일로 저장해놓거나 그렇습니다. 그리고 데이터베이스상에서도 그 사람이 언제 약관동의를 했는지 시간을 기록하는 컬럼이 있어야 나중에 법적 문제가 안 생깁니다.
※ Next에서는 redux설치시 App.js의 provider 태그 필요 없음
※ 리덕스: 데이터 중앙 저장소에서 관리하기 편하게끔(컴포넌트 단계 필요없이..) (contextAPI, Mobx, Apollo(GraphQL 등)), 액션들의 히스토리 관리(불변성을 유지하면서 새로운 객체를 만들어서 생성 ...state)
※ Flow: 1. front에서 이벤트 발생 --> dispatch 등으로 redux-saga로 (ex.watchLogIn) & 이와 동시에 reducer에서 switch 관련액션 동시에 실행됨(리듀서가좀빠름)--> saga에서 success되면 reducer에서 리듀서 함수 실행 --> 코드에 따라서 data 들어감 --> 그 영향이 다시 front로 건너감 ex. {isLoggedIn ? <UserProfile /> : <LoginForm />}
(Front => Sata => redux => saga => redux? => front)
※ 리덕스 사가
import {
all,
fork,
take,
takeEvery,
takeLatest,
throttle,
put,
delay,
} from "redux-saga/effects";
import axios from "axios";
import postSaga from "./post";
import userSaga from "./user";
//saga's generator
//const gen = function* () {console.log(1); yield; console.log(2); yield 4;}
//const generator = gen() --> 객체생성,
//generator.next() --> gen 실행 '1', 재실행 '2'(value: 4, done: true)
//중단점이 있는 함수(yield는 멈춤, yield뒤에 값: value)
//while(true){yield '무한';} : 무한반복이 아니라 매번 중단됨('무한', done:false)
//function* watchLogin(){yield take('LOG_IN', logIn)}
export default function* rootSaga() {
yield all([fork(postSaga), fork(userSaga)]);
}
//5. 여긴 generator함수 아님(data를 받아서 data와 함께 api에 넣음 - 바로 실행)!!
// data는 아래함수의 action.data
function logInAPI(data, a, b) {
return axios.post("/api/login", data);
}
function* logIn(action) {
//4. logIn 실행
//6. loginAPI를 실행시켜서 result로 결과를 받음
//put: dispatch와 같음(액션객체를 dispatch)
//call: 동기함수실행
//call이라 axios.post('api/login).then(()=>{yield put({type: ...})})
//fork였다면 그냥 axios.post('api/login)와 같음
//즉, API에 post한 다음 끝나면 다음것 put실행한다(fork면 명령내리고 받기전에 바로다음것)
//yield는 await과 비슷한데 fork는 이를 무시하게끔 즉시실행하는 것
try {
// loginAPI(action.data)과 같은뜻: 함수호출 방식이 call은 이렇게
// 첫번째자리가 함수, 그다음자리부터 매개변수(인수)
// 즉, action에서 data꺼내서 API함수에 전달
yield delay(1000);
// 임시보류 const result = yield call(logInAPI, action.data, "a", "b");
// 임시보류 yield put({ type: "LOG_IN_SUCCESS", data: result.data });
yield put({ type: "LOG_IN_SUCCESS" });
} catch (err) {
//7. 요청이 실패할 경우를 위해
yield put({
type: "LOG_IN_FAILURE",
data: err.response.data,
});
}
}
//8. 성공 결과는 result.data, 실패 결과는 err.response.data에 담김
//3. take: LOG_IN액션이 실행될때까지 기다리겠다. 그리고 logIn실행
// logIn관련된 매개변수(data)가 logIn()함수의 action에 전달
// action.type: LOG_IN_REQUEST, actin.data: login data 포함
function* watchLogIn() {
yield takeLatest("LOG_IN_REQUEST", logIn);
}
function logOutAPI() {
return axios.post("/api/logout");
}
function* logOut() {
try {
yield delay(1000);
// 임시보류 const result = yield call(logOutAPI);
yield put({
type: "LOG_OUT_SUCCESS",
// data: result.data,
});
} catch (err) {
yield put({
type: "LOG_OUT_FAILURE",
data: err.response.data,
});
}
}
//9. yield, take 단점: 딱 한번밖에 안받음(일회용) 한번쓰면 사라져버림(따라서 while로 감싸야)
// while, take는 동기적으로 동작, takeEvery는 비동기로 동작
// 직관적이지 않고 보기에 그래서 while대신 takeEvery로 동작
// takeLatest: ex. 실수로 로그인버튼 클릭두번 따닥시 takeevery는 둘다실행하기에 대체
// 첫번째것만 하고싶으면 takeLeading
// but, 응답을 한개 취소하는거지 요청을 취소하지는 않음 (요청 2개감)
// 이를 해결하기 위한 throttle, 3000(3초내에 딱 한번만 실행)
// throttle 잘 안쓰고 보통 takelatest하고 서버에서 요청을 검토해보고 막도록 함
// 10. 서버구현 아직 안해서 call logInAPI 다 에러날 것이라 delay로 임시대체
function* watchLogOut() {
yield takeLatest("LOG_OUT_REQUEST", logOut);
}
function addPostAPI(data) {
return axios.post("/api/post", data);
}
function* addPost(action) {
try {
yield delay(1000);
// 임시보류 const result = yield call(addPostAPI, action.data);
yield put({
type: "ADD_POST_SUCCESS",
// data: result.data,
});
} catch (err) {
yield put({
type: "ADD_POST_FAILURE",
data: err.response.data,
});
}
}
function* watchAddPost() {
yield takeLatest("ADD_POST_REQUEST", addPost);
}
//1. all: 배열 내의 것들을 동시실행(배열을 받음)
//2. fork, call: 함수실행 명령어(fork와 call의 차이점 존재함)
//fork: 비동기함수호출(기다리지않고 바로 다음것 실행), call: 동기함수호출(기다린후 실행)
export default function* rootSaga() {
yield all([fork(watchLogIn), fork(watchLogOut)]);
}
//# call, yield등을 쓰는 이유: test할 때 편함(a.next()함수실행으로 하나씩 버그검사, test코드 짜둬야 함)
· 컴포넌트 코딩 시작할때 순서
※ 컴포넌트상 index.js는 가장 중요하다고 생각하는 기능 삽입
※ styles.js: 스타일드컴포턴트 관련 파일
※ 배치하고 줄바꿔보고 공식문서 보고... 계속 반복
1 return에 값 넣기(1. 큼직하게 태그 만들기 - 이부분엔 닉네임, 이부분엔 뭐다...) - antd 참고
<NicknameEditForm />
<FollowList header="팔로잉 목록" />
<FollowList header="팔로워 목록" />
2. 데이터는 대충 Dummydata 만들기
const followerList = [
{ nickname: "제로초" },
{ nickname: "전세환" },
{ nickname: "김철수" },
];
3. 세부 구현 컴포넌트 만들기(Newfile 만들어서)
- 함수 등엔 userState, useCallback 사용 활용
· 폴더/파일명 나눌때
- 컴포넌트, 컨테이너 구분 X
- components폴더내에 form폴더, layout폴더 등등 재배치
· 직접적으로 스타일 간단하게 줄때(CSS)
<div style={{ marginTop: 10 }} > or
<div style={{ marginTop: '10px' }} > 이렇게 객체로 주면 안됨
(랜더링시 새로 생성되는데 객체로 주면 {} === {} false 다른값 나오므로 매번 이 부분도 리랜더링이 된다)
따라서 스타일드 컴포넌트를 주어야 함
만약 Antd의 태그를 새롭게 스타일하려면?
import styled from 'styled-components';
const SerchInput = styled(Input.Search)` //Input.Search는 antd에서 제공하는 태그명임
vertical-align: middle;
`
return(
<SerchInput enterButton></SerchInput>)
--> 이런식으로 컴포넌트 속성 받는 방식으로 적용!!
이 방식도 싫다면? --> useMemo 사용
useMemo 값을 캐싱하는 것
// import {useMemo} from "react";
// const style= useMemo(()=>({marginTop: 10}),[]);
// return(<Input.Search style={style}></Input.Search>)
// 리랜더링 방지하면서 style 꾸밀수 있게끔
· 로그인
· SNS로그인
· 이거 아니면 저거 보여주기
import UserProfile from "../components/UserProfile";
import LoginForm from "../components/LoginForm";
const [isLoggedIn, setIsLoggedIn] = useState(false);
return(
{isLoggedIn ? <UserProfile /> : <LoginForm />}
)
· 링크 새창에서 열기(target="_blank" rel="noreferrer noopener" 같이써야 보안위협 사라짐)
· 반응형 그리드 & 새창에서 띄우기:
모바일 먼저 세팅해서 기준으로 한다. / 가로먼저 자르고 세로로 자른다.
import { Row, Col } from "antd";
{/* Grid sys` sm(테블릿)*/}
{/* gutter: column사이의 간격*/}
<Row gutter={8}>
<Col xs={24} md={6} /> 왼쪽메뉴
<Col xs={24} md={12} /> {children}
<Col xs={24} md={6} />{" "}
<a href="https://www.zerocho.com" target="_blank" rel="noreferrer noopener">
Made by Zerocho
</a>
</Row>
· 검색창
import { Input} from "antd";
return(
<Input.Search
enterButton
style={{ verticalAlign: "middle" }}
></Input.Search>
※ 에러검토
TypeError: Cannot read property 'Posts' of null
--> 서버 껏다가 재시작
회원가입 관련 Front-end와 Back-end 정리 (0) | 2022.06.01 |
---|---|
react-quill 사용(이미지 포함)방법 (0) | 2022.05.29 |
노마드코더님 _ React #3 (0) | 2020.06.16 |
노마드코더강의_React#1 (0) | 2020.06.12 |
노마드코더 강의_React #2 (0) | 2020.06.12 |
댓글 영역