React 심화 주차

태권·2022년 9월 1일
0

개념알기

목록 보기
25/26

React 심화 주차 키워드

🔐 리덕스에서 미들웨어 청크의 역할은 뭘까요?

리덕스에서 dispatch를 하면 action 이 리듀서로 전달이 되고, 리듀서는 새로운 state를 반환합니다. 근데 미들웨어를 사용하면 이 과정 사이에 우리가 하고 싶은 작업들을 넣어서 할 수 있습니다.

리덕스 thunk란,

리덕스에서 많이 사용하고 있는 미들웨어중에 하나입니다. thunk를 사용하면 우리가 dispatch를 할때 객체가 아닌 함수를 dispatch 할 수 있게 해줍니다. 즉 dispatch(객체) 가 아니라 dispatch(함수)를 할 수 있게 되는 것

dispatch(함수)**함수실행** → 함수안에서 dispatch(객체)

툴킷에서는 createAsyncThunk 라는 API를 사용해서 thunk 함수를 생성할 수 있습니다. 이 API는 함수인데, 첫번째 인자에는 Action Value, 두번째 인자에는 함수가 들어갑니다. 이 함수에 우리가 하고 싶은 작업들을 구현하면 됩니다.

  • 리덕스 미들웨어를 사용하면, 액션이 리듀서로 전달되기전에 중간에 어떤 작업을 더 할 수있다.
  • Thunk를 사용하면, 객체가 아닌 함수를 dispatch 할 수 있게 해준다. [thunk의 핵심]
  • 리덕스 툴킷에서 Thunk 함수를 생성할 때는 *createAsyncThunk 를 이용한다.**
  • *createAsyncThunk() 의 첫번째 자리에는 action value, 두번째에는 함수가 들어간다.**
  • 두번째로 들어가는 함수에서 2개의 인자를 꺼내 사용할 수 있는데, 첫번째 인자는 컴포넌트에서 보내준 payload이고, 두번째 인자는 thunk에서 제공하는 여러가지 기능이다.

export const __getTodos = createAsyncThunk( "todos/getTodos", async (payload, thunkAPI) => { try { const data = await axios.get("http://localhost:3001/todos"); return thunkAPI.fulfillWithValue(data.data); } catch (error) { return thunkAPI.rejectWithValue(error); } } );

  • *fulfillWithValue 는 툴킷에서 제공하는 API 입니다.**

Promise에서 **resolve**된 경우, 다시 말해 네트워크 요청이 성공한 경우에 dispatch 해주는 기능을 가진 API 입니다. 그리고 인자로는 payload를 넣어줄 수 있습니다.

rejectWithValue 도 툴킷에서 제공하는 API 입니다.

Promise가 reject 된 경우, 네트워크 요청이 실패한 경우 dispatch 해주는 기능을 가진 API 입니다. 마찬가지로 인자로 어떤 값을 넣을 수 있습니다. 필자는 catch 에서 잡아주는 error 객체를 넣었습니다.

extraReducers: { [__getTodos.pending]: (state) => { state.isLoading = true; // 네트워크 요청이 시작되면 로딩상태를 true로 변경합니다. }, [__getTodos.fulfilled]: (state, action) => { state.isLoading = false; // 네트워크 요청이 끝났으니, false로 변경합니다. state.todos = action.payload; // Store에 있는 todos에 서버에서 가져온 todos를 넣습니다. }, [__getTodos.rejected]: (state, action) => { state.isLoading = false; // 에러가 발생했지만, 네트워크 요청이 끝났으니, false로 변경합니다. state.error = action.payload; // catch 된 error 객체를 state.error에 넣습니다. },

🔐 프로미스는 정확히 말하면 비동기가 아닙니다. 비동기와 프로미스는 각각 무엇일까요?

https://elvanov.com/2597 여기서 찾아보았다.

비동기는 여러 작업이 있을때 순서대로 일어나는것이 아니라 각각 따로 일어나서 먼저 완료되면 실행이 되는것이다.

이때 함수들이 서로 다른 함수의 값을 참조하거나 할때 참조할 값의 함수가 완료가 안되면 그 다음 함수가 실행이 안되거나 오류가 날 수 있어서 그 함수 안에 콜백 함수로 넣어주게 되고 이렇게 콜백을 넣고 넣고 넣고 하다보니 콜백지옥이 생기게 되고

Promise 의 의의.

Promise는 비동기 작업을 생성/시작하는 부분(new Promise(...))과 작업 이후의 동작 지정 부분(thencatch)을 분리함으로써 기존의 러프한 비동기 작업보다 유연한 설계를 가능토록 합니다.

먼저 실행되지않고 기다렸다가 불러와지면 실행하게 되는것이다.

이렇게 Promise를 만드는 방법은 async와 await이다

함수에 async를 하면 비동기 작업을 하게 되고 Promise를 반환하게 된다.

이 함수 안에서 then과 catch를 써도 되지만 await를 써서 작업을 기다리고 불러와지게 되면 그값을 가져오는 식으로 쓸 수 있다.

🔐 TDZ(Temporal Dead Zone/일시적 사각지대)란?

스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 TDZ(Temporal Dead Zone) 라고합니다.

Untitled

let 또한 선언전, 실행 컨텍스트 변수 객체에 등록이 되어 호이스팅이 되지만,

이 TDZ 구간에 의해 메모리가 할당이 되질 않아 참조 에러(ReferenceError) 발생하는 것 입니다.

DIY Section

🔑 Q1. axios 와 json-server로 CURD

일단 axios를 import 해오고

json-server도 만들었다고 생각하고 하면

axios는 두가지 형태로 나타낼수 있는데

axios({})

axios.get()

두 형태로 만들 수 있다 위 방식으로 하면 안에 method랑 헤더에 들어갈 내용 post일 경우 가져갈 데이터를 넣을 수 있고

아래 방식으로 하면 첫번재로 url을 가지고 두번째 인자로 옵션을 정해줄 수 있다.

const load_bucket = async ()=>{
    const res = await axios.get("http://localhost:5001/bucket")
    dispatch(loadBucket(res.data));
    
  }
const addBucketList = async() => {
    const newlist = { text: text.current.value, Done: false };
    await axios.post("http://localhost:5001/bucket",newlist)
    distpatch(createBucket(newlist));
    resetplace();
  };
const delete_bucket = async id => {
    await axios.delete(`http://localhost:5001/bucket/${id}`);
    dispatch(deleteBucket(id));
  };
const update_bucket = async (id, text) => {
    const data = { Done: !mylist[0].Done };
    const res = await axios.patch(`http://localhost:5001/bucket/${id}`, data);
    console.log(res.data);
    dispatch(updateBucket(id));
  };

위에는 CURD의 예시로

get으로 가져올때 쿼리 파라미터로 해당아이디를 지정하거나 조건을 정해서 가져올 수 있다.

하지만 나머지 방식에서는 쿼리파라미터로 id값만 지정할 수 있다.

업데이트 방식에는 put과 patch가 있는데 둘의 차이는 put은 그 아이디값의 자료를 가져온 자료로 아예 다 바꿔버리고

patch는 가져온 값에 해당 하는것만 바꿔주는 형식이다.

그리고 axios를 사용하면 서버의 데이터를 바꾸고 불러오기 때문에 axios를 통해 데이터를 바꾸어도

리렌더링이 되지않는다 그래서 리덕스를 사용하여 값을 저장해주고 리렌더링이 되게 만들어 주어야 한다.

이게 아니면 axios와 리덕스를 합친 느낌의 리액트 쿼리가 있다.

리액트 쿼리는 클라언트에서 데이터를 갱신하고 그러지 않고 서버에서 다 해준다고 생각한다.

🔑 Q2. axios로 pagination
const commentList = useSelector((state) => state.comments.list);

  const [isUpdate, setIsUpdate] = useState(true);
  // const [updateComment, setUpdateComment] = useState("");
  const [postcomment, setpostcomment] = useState(commentList);
  const [currentPage, setCurrentPage] = useState(1);
  const [commentCount] = useState(4);

  const commentLength = commentList.length;
  const maxPage =
    Math.ceil(commentLength / commentCount) === 0
      ? 1
      : Math.ceil(commentLength / commentCount);
  const lastIndex = currentPage * commentCount;
  const firstIndex = lastIndex - commentCount;
  console.log(commentList);

  React.useEffect(() => {
    setpostcomment(commentList.slice(firstIndex, lastIndex));
  }, [currentPage, commentCount]);
<div className="flex justify-between">
          <button
            disabled={currentPage <= 1}
            onClick={() => {
              setCurrentPage(currentPage - 1);
            }}>
            이전댓글
          </button>
          <div>{`${currentPage}/${maxPage} `}</div>
          <button
            disabled={currentPage >= maxPage}
            onClick={() => {
              setCurrentPage(currentPage + 1);
            }}>
            다음 댓글
          </button>
        </div>

pagination에도 방식이 2가지가 있을꺼 같다

첫 방식은 해당 카드 내용의 댓글을 다 가져와서 클라이언트 부분에서 만드는 것과

두번째 방식은 댓글을 불러올때 axios에서 이미 불러올 댓글을 처리해서 만드는 방식이 있다

일단은 댓글양이 많지 않아서 첫 방식으로 했는데 다음에는 다른 방식으로 구현해 보겠다.

🔑 Q3. 다른 사람과 협업할때 clone후 방법과 자주쓰이게 되는 git 명령어

다른 팀원들과 협업을 제대로 하기 시작한 첫주가 된거같다 그전에는 다 따로 만들고 했지만 이번부터 같이 미니프로젝트를 만들면서 git 명령어를 정리해봤다.

일단 처음으로 설정을 해준다

git config --global user.name 닉네임
git config --global user.email 이메일

git cofig --global init.defaultBranch main

협업을 위해 클론을 만들어준다.

git clone 주소

이후에 따로 브랜치를 만들어서 main에 바로안올라가게 해준다.

git switch -c 이름

이후에 파일을 손보고

git add . .이면 전부 다 올리고 일부만 올릴려면 “파일 이름 ” 해주면된다

그리고 커밋

git commit -m “메세지”

해준다음

git push origin HEAD 하면 지금 브랜치가 깃허브에 연동되서 올라가지고

깃허브가서 PR 해주면 된다.

이후 main으로 switch 해주고

git pull 해준다.

이후 브랜치를 지우고 싶다면

git branch -D 브랜치

이고 원격 브랜치를 지우고 싶다면

git push origin —delete 브랜치 로 하면된다.

다른사람이 브랜치 만들었다면

git fetch로 업데이트 해서

git branch -a 하면 원격에 있는 브랜치 까지 다 볼 수 있다.

🔑 Q4. useCallback

useMemo 는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback
은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용합니다.

컴포넌트의 결과물을 재사용 하는 최적화 작업

const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
const { username, email } = inputs;
const onChange = useCallback(
    e => {
      const { name, value } = e.target;
      setInputs({
        ...inputs,
        [name]: value
      });
    },
    [inputs]
  );

const onRemove = useCallback(
    id => {
      setUsers(users.filter(user => user.id !== id));
    },
    [users]
  );

콜백함수는 다른 함수와 형태는 비슷하다고 생각하고

마지막에 의존성 배열이 추가되는것이라고 생각이된다.

그래서의존성 배열이 변하게되면 다시 불러오게 되고 그게 아니라면 그 함수를 그대로 가지고 있는다.

🔑 Q5. customHook

커스텀 Hooks 를 만들 때에는 보통 이렇게 use 라는 키워드로 시작하는 파일을 만들고 그 안에 함수를 작성합니다.

import { useState, useCallback } from 'react';

function useInputs(initialForm) {
  const [form, setForm] = useState(initialForm);
  // change
  const onChange = useCallback(e => {
    const { name, value } = e.target;
    setForm(form => ({ ...form, [name]: value }));
  }, []);
  const reset = useCallback(() => setForm(initialForm), [initialForm]);
  return [form, onChange, reset];
}

export default useInputs;
const [datas, onChange, reset] = useInputs({
        nickname: "",
        content: "",
    });

이렇게 useInputs 안에있는 데이터와 함수를 불러온다.

onChange는 input 태그안에 onChange안에 넣어주면 변화된값을 가져오고

reset은 데이터를 보낼때 마지막으로 넣어주면 값이 초기화된다.

다른 예시

const useAxios = () => {
    const [state, setState] = React.useState({
        data: null,
        error: null,
        loading: false,
    });

    const loadData = async (axios) => {
        setState({ data: null, error: null, loading: true });
        try {
            const responseData = await axios;
            if (responseData) {
                setState({
                    data: responseData.data,
                    error: null,
                    loading: false,
                });
                return responseData;
            }
        } catch (error) {
            setState((prevState) => ({ ...prevState, error, loading: false }));
            throw error;
        }
        return null;
    };

    const clear = () => {
        setState({ data: null, error: null, loading: false });
    };

    return { ...state, loadData, clear };
};

export default useAxios;
const axiosState = useAxios();
const addComment = async () => {
        const { data } = await axiosState.loadData(
            restApi.post("comment", {
                ...datas,
                is_deleted: false,
                todo_id: params.id,
                created_at: toStringByFormatting(new Date()),
            })
        );
        reset();
        window.location.reload();
    };

restApi는 axios instance이고 loadData를 가져와서 안에 axios를 넣어주면 그값을 반환 하여 data에 넣어준다.

profile
2022.08 개발자 시작

0개의 댓글