관리 메뉴

Jerry

til #24 본문

자기 성찰/TIL

til #24

juicyjerry 2021. 8. 10. 19:35
반응형

 

 

 

redux-toolkit는 리덕스에서 많이 쓰이는 라이브러리를 모아놓은 것

  • thunk, saga, immer 다 내장되어있어 따로 안 싸도 된다.
  • action creator도 toolkit이 만들어준다.
  • toolkit에서 action 항목에서 fulfiiled는 payload, rejected는 error에 requestId가 있는데 요청별로 다른 id를 부여해 같은 짝을 찾을 때 참고하면 유용하다
  • immer 쓰다가보면 가끔씩 불변성이 깨지는 경우가 있는데 그럴 땐, 해당 변수 리턴문을 추가한다.

 

 

 

 

cf) 자바스크립트에서 논블로킹으로 delay를 구현하는 방법은 setTimeout과 Promise밖에 없습니다. setTimeout에 await를 못 붙이니 Promise밖에 쓸 것이 없습니다. 

 

 

 

 

하나의 컴포넌트 안에서 리덕스 코드를 쓸 때와 쓰지 않아도 될 때 구분 (1. input, 2. async)

 

1. input

 

 

 

 

이게 의미가 있나? 마지막 값만 받아도 되는데 말이다.

위와 같은 상황은 리덕스 할 때 가장 많이 하는 실수 중 하나로 글자 하나하나 칠 때마다 액션 호출하면 변수 user가 매번 리렌더링 된다.

 

 

 

마지막 값을 받기 위해서 input들을 다 dispatch하지 말고  onBlur 속성을 이용하거나 input이 해당 컴포넌트에만 영향을 미치는 경우, state를 만들어서 state에 저장해서 마지막 한 번만 reducer로 보내주는 방법이 있다.

 

 

 

 

const user = useSelector((state) => state.user);

const onChangeEmail = useCallback((e) => {
    dispatch(userSlice.actions.setEmail(e.target.value));
    // setEmail(e.target.value);
  }, []);

  const onChangePassword = useCallback((e) => {
    dispatch(userSlice.actions.setPassword(e.target.value));
    // setPassword(e.target.value);
  }, []);

 

 

 

 

initialState이게 state.user이며, email, password를 destructuring해서 사용할 수 있다.

useSelector는 user가 바뀔 때 해당 함수 컴포넌트를(App) 리렌더링 시킨다. 

user는 state.user안에 내용이 바뀌어야 리렌더링 된다

 

 

 

 

반대로, 한 글자씩 추가되면 리렌더링 되고 useState도 똑같은거 아닌가요?

비교해보면, useSelector는 다른 컴포넌트에서 사용자 정보를 위해 사용할 수 있는데

만약, email이나 password가 위와 같이 추가가 되면 다른 모든 컴포넌트들도 리렌더링이 된다.

그래서 useSelector가 useState보다 문제가 더 발생한다.

 

 

 

// App.jsx
const { email, password } = useSelector((state) => state.user);

// userSlice의 initialState
const initialState = {
  isLoggingIn: false,
  data: null,
  email: "",
  password: "",
};

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");

 

 

 

 

이 걸 막을려면, 객체로 써주지 말고 하나하나씩 꺼내서(쪼개서) 사용하는게 좋다.

그럼 변경된 부분에 한하여 리렌더링된다. 

리턴하는 값이 객체가 아니고 문자열, 불린값 같은 원시값이면 문제가 크게 발생하지 않는다.

 

 

 

// App.jsx
const email = useSelector((state) => state.user.email);
const password = useSelector((state) => state.user.password);
const isLoggingIn = useSelector((state) => state.user.isLoggingIn);
const data = useSelector((state) => state.user.data);

 

 

 

속성이 많을수록 위에서 설명한 것처럼 다 풀어서 쓰기도 그렇잖아요. 그래서 타협해서 아래처럼 사용하는 거에요.

 

 

 

나는 리렌더링이 많이 일어나지만 성능에 문제가 없을거야라고

 

 

 

 const { email, password } = useSelector((state) => state.user);

 

 

 

cf) 최적화는 미리하는게 좋다?
NO, 처음부터 최적화 해주는게 좋지 않아요. 체감이 될 때(타자 버벅, 화면 전환 느림) 해도 늦지 않아요.
좋고 문제가 없을 때부터 지나치게 최적화하면 하면 할수록 변화에 대처하기 힘들어요(기획이 변할 때).

 

 

 

 

 

2. async(비동기)

비동기 요청을 보내는 것이, 예를 들어 로그인이 해당 컴포넌트에서만 실행이 되는 경우(다른 컴포넌트에 영향을 끼치지 않는다면)

리덕스 비동기 액션으로 만들지말고, 바로 axios로 요청보내세요. (#1말고 #2처럼) 대신, 리덕스처럼 비슷해야해요. (#3)

 

 

 

// #1
const logIn = createAsyncThunk("user/logIn", async (data, thunkAPI) => {
  console.log(data);
  // throw new Error("비밀번호가 틀렸습니다.");

  const response = await axios.post('/login', {email, password});
  const result = await delay(500, {
    userId: 1,
    nickname: "zerocho",
  });
  return result;
});

module.exports = {
  logIn,
};

// #2
dispatch(
      // 실제로는 인풋이랑 연결되어있는데 여기선 더미데이터로 테스트
      logIn({
        id: "zerocho",
        password: "비밀번호",
      })
    );
    axios.post("/login")
  }, []);

// #3
const [isLoading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  const [done, setDone] = useState(false);

  const onClick = useCallback(async () => {
    setLoading(true); // 로딩창용
    setDone(false);
    setError(false);

    try {
      const response = await axios.post("/login");
      setDone(true);
    } catch (error) {
      setError(error);
    } finally {
      setLoading(false); // 로딩창은 꺼야죠
    }

    await axios.post("/login");
  }, []);

 

 

 

 

 

 

 

 

반응형

'자기 성찰 > TIL' 카테고리의 다른 글

til #27  (0) 2021.08.18
til #26  (0) 2021.08.17
til #23  (0) 2021.08.07
til #22  (0) 2021.08.05
til #21  (0) 2021.07.31