React/NodeBird(ZeroCho) 22

eslint로 프로젝트 점검하기

프로젝트 에러를 잡을 때 엄격하게 하기 위해서 eslint를 이용해서 프로젝트를 점검해보자. 아래 명령어를 설치해주고 npm i -D babel-eslint eslint-config-airbnb eslint-plugin-import npm i -D eslint-plugin-react-hooks .eslintrc 파일도 아래와 같이 parser babel-eslint를 추가하여 babel이 코드를 해석해서 최신문법도 에러를 발생시키지 않게 하자. extends 부분도 airbnb(airbnb사가 강한규제로 유명함)로 설정하여 스타일을 강한 규제에 놓이도록 하자. { "parser": "babel-eslint", "parserOptions": { "ecmaVersion": 2020, "sourceType":..

saga 쪼개고 reducer와 연결하기

saga의 단점은 코드줄이 매우 길어진다는 것이다. logIn만 해도 그렇다. action 하나당 3개씩 세트이기 때문에 add comment follow like unlike unfollow 이런 것들이 action 3개씩 나온다. 그래서 이제 saga를 한번 나눠보자.. function logInAPI(data) { return axios.post("/api/login", data); } function* logIn(action) { try { // const result = yield call(logInAPI, action.data); yield delay(1000); yield put({ type: "LOG_IN_SUCCESS", }); } catch (err) { yield put({ type:..

take 시리즈, throttle 알아보기

아래코드 yield take의 단점은 일회용이라는 것이다. 그래서 한번 LOG_IN_REQUEST 하면 로그인 실행되고 LOG_OUT_REQUEST 하면 로그아웃 실행되고 한다. 그런데 take를 써서 한번밖에 받지 않으니까 한 번 로그인 했다가 한번 로그아웃하면 그 다음 로그인 할 때는 이벤트 리스너가 사라져 버리게 된다. // sagas 폴더안에 index.js function* watchLogin() { yield take("LOG_IN_REQUEST", logIn); } function* watchLogout() { yield take("LOG_OUT_REQUEST", logOut); } function* watchAddPost() { yield take("ADD_POST_REQUEST", add..

saga 이펙트 알아보기

all fork call put 요런 것들에 대해서 알아보자. 얘네들을 saga의 이펙트라고 부른다. 그래서 보통 rootSaga() 하나 만들어 놓고 거기에 비동기 액션들을 하나씩 넣어준다. thunk처럼 async action creator라고 표현하기엔 좀 그렇고 한번 비교를 해보자. // sagas폴더에 index.js import { all, fork, call, put } from "redux-saga/effects"; export default function* rootSaga() { yield all([ fork(watchLogin), ]); } rootSaga()안에 all은 배열을 받는데 배열을 받으면 그 배열안에 들어있는 것들을 한방에 다 실행을 해준다. 그러면 아래 watchLogi..

saga 설치 & generator 이해하기

이전에 진행했던 thunk를 지우고 saga를 설치해주자. npm rm redux-thunk npm i redux-saga 그리고 createMiddleware를 import 해서 변수에 넣고 아래와 같이 넣어준다. // reducers 폴더안에 configureStore.js파일 코드 일부분 import createSagaMiddleware from "redux-saga"; const configureStore = () => { const sagaMiddleware = createSagaMiddleware(); const middlewares = [sagaMiddleware, loggerMiddleware]; sagamiddleware는 살짝 기능이 조금 더 있다. 아래 코드를 보자. rootsaga는..

redux-thunk 이해하기

NodeBird 클론코딩을 진행하였는데 antd을 이용해서 sns 화면을 만들어주고 Redux도 연동하여서 더미데이터와 게시글 댓글 이미지도 구현하고 해시태그 링크도 만들어 주었다. (정리는 차후에 하자...) 이제는 Redux-saga를 연동해주면서 프로젝트를 진행해줄 것인데, redux-thunk 부터 이해를 하자.(redux-thunk말고 redux-saga는 나중에 알아보자.) redux-thunk는 redux의 middleware로써 (여기1와 여기2를 보고 참고하자.) redux-thunk는 redux가 비동기 dispatch할 수 있도록 도와주는 역할을 한다. thunk는 프로그래밍 용어이다. 지연된 함수를 뜻한다. thunk 공식문서인 여기를 한 번 보자. 아래 코드를 보자. increme..

정규표현식 맛보기

여기서 정규표현식을 갖고 놀아보자. 일단 정규표현식은 다양한 경우를 고려해야 한다. 아래와 같이 해시태그 사이에 띄워쓰기가 있을 수도 있고 띄워쓰기가 없을 수도 있다. 어떤 사용자는 #을 연달아 적고 아래와 같이 쓸 수도 있다. 사용자들이 각양각색의 방법으로 글을 쓸 수가 있기 때문에 내가 원하는 의도와 일치하는지 체크를 해보는게 좋다. 일단 뒤에 g가 붙냐 안붙냐가 강건인데 g가 붙으면 여러개이고 g가 안붙으면 하나만 뜻한다. 해시태그를 여러개 찾아야하는 나의 입장에서 g를 붙여준다. #을 하면 문자 그대로 #을 뜻한다. #들이 모두 선택이 되고 g를 빼보면 첫번째 #만 선택된다. 그리고 . 하나를 붙이면 모든 글자 중에서 한글자가 선택되고 ... 세개를 붙이면 3글자가 선택된다. 길이가 항상 3개로 ..

리덕스의 원리와 불변성

redux는 reduce에서 이름을 따온 것이다. 데이터 중앙 저장소가 있다고 쳐보자. 아래 그림에다가 name은 jay, age: 27, password는 babo가 들어있다고 하자. 중앙저장소를 만들면 이걸 각 컴포넌트에서 필요로 할 때 꺼내서 쓸 수 있다. 데이터를 조회하기만 하는 것이 아니라 데이터를 수정도 하고 데이터를 추가도 하고 삭제도 한다. 리덕스에서는 데이터를 바꾸려면 action이라는 것을 필수로 만들어 줘야한다. 가상의 action 하나가 있다고 치면 (아래와 같이) 중앙저장소가 있고 이 중앙저장소를 수정해야 되는 일이 있는데 그럴 때 액션을 또 하나 만들 수 있다. 그리고 이 액션을 dispatch하면 중앙저장소가 바뀐다. 즉 action을 dispatch 하는 순간 CHANGE_N..

redux설치

프로젝트에 리덕스를 붙이려면 복잡한 과정을 거쳐야 하고 실제로 next에서도 리덕스를 붙일 때 많이 복잡하다. 이것을 간편하게 해주는 라이브러리가 있는데 next redux wrapper이다. (여기서 확인하자. 최신버전으로 올라와서 next 9버전에서도 사용할 수 있다.) 일반 리덕스와는 동작이 다른데 진행중인 프로젝트 안에서(prepare-front-store폴더구조) store폴더로 들어가서 configureStore.js파일 생성한다. next redux wrapper도 버전이 올라가면서 예전과는 사용방법이 달라졌기 때문에 버전을 항상 조심하자. // configureStore.js const configureStore = () => { }; const wrapper = createWrapper(..

회원가입 페이지 만들기(커스텀 훅)

signup.js에서 AppLayout로 일단 한번 감싸준다. antd 자체에 Form태그가 있기 때문에 임포트 해준다. 알다시피 onFinish는 내부적으로 e.preventDefault가 자동으로 되기 때문에 따로 할 필요가 없다. signup.js는 아래와 같이 해주고 // signup.js import React, { useCallback, useState } from 'react'; import Head from 'next/head'; import { Form, Input } from 'antd'; import AppLayout from '../components/AppLayout'; const Signup = () => { const [id, setId] = useState(''); const..