항해 99를 하면서도 많이 부족해서 시도해보지 못하고 Toastify를 사용했었지만 이번 기회에 전역상태관리를 이용해서 모달을 만들어 보고 싶어 도전하게 되었다.

 

참고로 전역모달에 관련된 코드는 지인 분들 중 한 분에게 도움을 요청을 했었다.

(선뜻 친절하게 설명해준 승구쓰 ㅠㅠ) 

 

혼자서 며칠동안 코드를 수정하며 만들어 보게 되었고 결국 돌고 돌아 내가 원하는 기능을 넣게 되었다.

 

처음으로 내가 만들어 보고 싶었던 것은 [좋아요 모달] 이었다. 

 

상품 정보가 있는 공간에 좋아요 버튼을 누르게 되면 화면 하단에서부터 애니메이션 효과를 내며 올라오는 모달!

 

직접 어떤 효과가 어울리고 다른 쇼핑몰에서는 어떻게 구현을 하고 있는 지 어플들을 깔아 확인도 해보고 react-native에서 지원하는 Animated를 공부해보기도 하고..

 

 

대략적인 흐름은 다음과 같이 만들었다.

좋아요 버튼 클릭 > 상태 저장 > 구독하고 있던 전역 모달 컴포넌트에서 업데이트 > 여러 모달 중 상태값에 따라 해당 모달에 데이터 전달 > 모달 팝업

 

내가 실행시키고 싶은 모달의 type과 함께 필요한 상태값을 스토어에 저장을 하게 되면 전역 모달 컴포넌트에서 상태를 업데이트 받아 해당 모달에 props를 전달하는 방식이다.

 

 

우선 모달을 열고 닫기 위해 커스텀 훅으로 openModal과 closeModal을 만들어 사용했다.

 

function useModal() {
  const dispatch = useDispatch();

  const handleOpenModal = (modalType: string, props: any) => {
    dispatch(openModal(modalType, props));
  };

  const handleCloseModal = (modalType: string) => {
    dispatch(closeModal(modalType));
  };

  return { openModal: handleOpenModal, closeModal: handleCloseModal };
}

export default useModal;

 

 

좋아요 버튼을 클릭하면 openModal을 실행하고 스토어에 해당 상품의 좋아요 상태를 넘겨주었다.

스토어에서 modal reducer에 실행된 액션함수에 따라 리듀서에 상태값을 저장하거나 업데이트 처리를 하게 된다.

(좋아요 는 likes reducer에서 사가를 활용하여 좋아요 상태를 저장함과 동시에 서버에 상품의 좋아요 상태를 업데이트하는 비동기처리가 되어있다.)

 

 

export const openModal = (modalType: string, props: {}) => ({
  type: MODAL,
  payload: { modalType, isOpen: true, props },
});

export const closeModal = (modalType: string) => ({
  type: MODAL,
  payload: { isOpen: false },
});


const initialState: ModalActionType<{}> = {
  modalType: "",
  isOpen: false,
  props: {},
};


const modalState = (state = initialState, action: Action<ModalActionType>) => {
  switch (action.type) {
    case MODAL:
      return {
        ...state,
        modalType: action.payload.modalType,
        isOpen: action.payload.isOpen,
        props: action.payload.props,
      };
    default:
      return state;
  }
};

export default modalState;

 

 

 

그렇게 상태저장이 완료가 되면 스토어를 구독하고 있던 컴포넌트에서 업데이트받은 상태값으로 팝업시킬 모달을 찾아 처리한다.

 

 

 

export default function GlobalModal(): JSX.Element {
  const { modalType, isOpen, props } = useSelector(
    (state: ModalState) => state.modal
  );

  if (!isOpen) {
    return <></>;
  }

  const MODAL_COMPONENTS: { [key: string]: JSX.Element } = {
    alarm: <LikeNotification props={props} />,
  };
  return <View>{MODAL_COMPONENTS[modalType]}</View>;
}

 

 

진짜 리액트 네이티브 css도 지원안되는 거 많고 기능은 또 어떻게 구현해야하고 하는 문제때문에 허송세월을 얼마나 보냈는가..

리액트 네이티브의 css속성은 %지원이 되지않아 translate px단위로 사용하려다보니 포기하고 화면 크기를 가져와서 게산을 해야하는 등.. 까다로운 부분이 꽤나 있었다.

 

 

 



좋아요 모달을 만들면서 겪었던 트러블 슈팅 두 가지

 

트러블 슈팅1.

 

모달이 하단 y축의 60의 위치(하단탭바의 높이)에서 -5 위치까지 0.5초의 시간을 두고 올라온다. 좋아요 모달은 2초후에 사라지게 설정을 해놓았다.

 

처음에는 isLiked 상태값만 가져와서 useEffect의 의존성배열에 추가를 했었는데..(좋아요상태가 변하면 올라오니까 당연하게 생각해버림) 

 다른 상품들 중 내가 누른 좋아요 버튼의 상태와 같은 버튼이 있을 경우 모달은 팝업되지 않았다는 문제가 있었다.

 

결국 상품의 아이디를 받아와서 함께 의존성 배열에 추가하여 좋아요 상태가 변하거나 상품의 아이디가 변할때 모달이 팝업되게 수정을 하여 해결하였다.

 

 

트러블 슈팅2.

 

setTimeout을 useState에 담아 사용을 했더니 좋아요 버튼을 연속클릭 시 상태값이 저장되면서 리렌더링이 일어나게 되었다.

 

각 클릭마다 타이머가 생성되고 실행되어 결국 나중에 올라온 모달이 2초가 되기도 전에 사라지게 되었다.

 

이 문제는 useRef를 사용하여 리렌더링 되는 문제를 해결하고 이전 타이머를 취소하여 업데이트할 수 있게 되었다.

 

리렌더링 문제를 제외하고 여러 사건사고들이 많았지만 가장 어이가 없었던 상황이 생각이 난다.

버튼을 클릭할때마다 아래에서 위로 모달이 새로 올라오지 않고 위에 떠 있는 상태에서 텍스트만 바뀌고 있어서 몹시 당황스러웠다.

내가 생각했던 건 이거 아닌데..?

결국, 이 상황은 useEffect에서 컴포넌트가 종료되기 전에 모달의 y축위치를 수정하는 코드를 추가하여 애니메이션 효과를 처음부터 실행함으로써 해결할 수 있었다.

 

사실 코딩 실력이 많이 부족한 나로서 어떻게든 기능 구현을 위해서 영차영차 달린 것이긴 하지만.. 부족하게나마 구현을 했다는 사실에 기뻐하며 행복했다   

 

'TIL & WIL' 카테고리의 다른 글

react-native 트러블 슈팅  (0) 2023.06.06
230221_TIL  (0) 2023.02.21
230217_TIL  (2) 2023.02.18
230213_TIL  (0) 2023.02.14
230204_TIL  (1) 2023.02.04

 

맨땅에 헤딩하듯 공부하면서 힘들었던 만큼 시간이 지났음을 느낀다. 부족해보이는 코드가 부끄럽지만 이번에 겪은 트러블 슈팅을 적어보려 한다.

 

트러블 슈팅 1.

Navigator

    ㄴ Home - Main,Best,New,Sale

    ㄴ Category

   ...

 

현재 상황

메인(Home) 화면에서 렌더링 할 때 상품의 전체 데이터를 서버에서 가져온 다음 state에 저장 후 하위 탭바의 컴포넌트로 전달하고 있는 상황.

 

상단 탭바에 있는 다른 탭을 눌렀다가 홈을 클릭할때 마다 이미지가 번쩍이는 효과가 발생.

 

이게 뭐지 싶어서 고민을 해보게 되었다. 탭을 누를 때 마다 서버에서 다시 전체데이터를 불러오는 건가?

 

export default function Home() {
  const layout = useWindowDimensions(); //TabView 컴포넌트에서 초기 레이아웃 설정을 위해서
  const [index, setIndex] = useState(0);
  const [productInfo, setProductInfo] = useState<ProductType[]>([]);
  const [routes] = useState([
    { key: "home", title: "홈" },
    { key: "best", title: "BEST" },
    { key: "new", title: "NEW" },
    { key: "sale", title: "SALE" },
  ]);


  const fetchDataFromServer = async () => {
    try {
      const response = await fetchProductData();
      setProductInfo(response);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    fetchDataFromServer();
  }, []);

  const HomeCategory = () => <Main productInfo={productInfo} />;
  const BestItemsCategory = () => <BestItems productInfo={productInfo} />;
  const NewItemsCategory = () => <NewItems productInfo={productInfo} />;
  const SalesCategory = () => <SaleItems productInfo={productInfo} />;

  const renderScene = SceneMap({
    home: HomeCategory,
    best: BestItemsCategory,
    new: NewItemsCategory,
    sale: SalesCategory,
  });


  return (
    <View style={{ flex: 1, backgroundColor: "white" }}>
      <TabView
        renderTabBar={(props) => (
          <Bar
            {...props}
            style={{
              backgroundColor: "unset",
            }}
            labelStyle={{ color: "black" }}
            pressColor="transparent"
            indicatorStyle={{ backgroundColor: "black" }}
            renderLabel={({ route, focused }) => (
              <TabText focused={focused}>{route.title}</TabText>
            )}
          />
        )}
        navigationState={{ index, routes }}
        renderScene={renderScene}
        onIndexChange={setIndex}
        initialLayout={{ width: layout.width }}
      />
    </View>
  );
}

 

하지만 상위 컴포넌트에서 props로 전달하는 방식이라 탭을 클릭했을 때 서버의 전체 데이터를 받아와서 적용되는 것은 아니라고 생각이 들었고,  이미지가 도대체 왜 번쩍이는지 전혀 이해를 못하고 있었다.

 

원인 발견

상단 탭바(react-native-tab-view)에서 각각의 탭들을 클릭할 때 react-native-tab-view는 현재 index를 렌더링하게 된다.

즉, 홈(Main) 탭을 클릭 할 때, 렌더링이 되기 때문에 이미지가 번쩍이는 효과가 나타는 것.

 

해결 방법

각 탭에 대한 컴포넌트들을 캐싱하는 방식으로 구현하기 위해  useMemo를 사용하였다.

 

/*
  const HomeCategory = () => <Main productInfo={productInfo} />;
  const BestItemsCategory = () => <BestItems productInfo={productInfo} />;
  const NewItemsCategory = () => <NewItems productInfo={productInfo} />;
  const SalesCategory = () => <SaleItems productInfo={productInfo} />;

  const renderScene = SceneMap({
    home: HomeCategory,
    best: BestItemsCategory,
    new: NewItemsCategory,
    sale: SalesCategory,
  });
*/


const HomeCategory = useMemo(
    () => <Main productInfo={productInfo} />,
    [productInfo]
  );
  const BestItemsCategory = useMemo(
    () => <BestItems productInfo={productInfo} />,
    [productInfo]
  );
  const NewItemsCategory = useMemo(
    () => <NewItems productInfo={productInfo} />,
    [productInfo]
  );
  const SalesCategory = useMemo(
    () => <SaleItems productInfo={productInfo} />,
    [productInfo]
  );

  const renderScene = ({ route }: { route: { key: string } }) => {
    switch (route.key) {
      case "home":
        return HomeCategory;
      case "best":
        return BestItemsCategory;
      case "new":
        return NewItemsCategory;
      case "sale":
        return SalesCategory;
      default:
        return null;
    }
  };

 

route객체는 왜 받고 route.key는 또 뭐야?

rednerScene의 route.key는 TabView에서 현재 활성화된 탭에 해당하는 컴포넌트를 렌더링하기 위해 routes라는 useState 값을 사용 중이다.

routes = [{ key: ... , title: ...},{...}]

 

 

 

 

트러블 슈팅 2.

Navigator

    ㄴ Home 

          ㄴ Main

                 ㄴ ProductList

 

 

현재 상황

상품의 리스트를 나타내는 컴포넌트인 ProductList에서 좋아요 버튼을 눌렀을 때 서버에 좋아요 상태를 변경함.

상태를 변경할때마다 서버에서 데이터를 다시 불러와서 적용하는 것은 지양하고 싶었기 때문에, 로컬에서 setState를 사용하여 좋아요 상태를 변경하여 다시 적용하려 의도 함.

 

export default function ProductList({ products }: ProductListProps) {
  const [productsData, setProductsData] = useState(products);

  const toggleProductLikedStatus = ({ productId, currentIsLiked }: LikesProductType) => {
      updateProductLikedStatus({
        productId,
        isLiked: currentIsLiked,
      });
      setProductsData((prevProducts) => {
        return prevProducts?.map((product) => {
          if (product.id === productId) {
            return {
              ...product,
              isLiked: !product.isLiked,
            };
          }
          return product;
        });
      });
    };
 
  return (
    <Wrapper>
      {productsData?.map((product) => {
        return (
          <ProductCard key={product.product_name}>
            <ImageContainer>
              <Img source={{ uri: product.image }} />
              <LikesBtn
                name={product.isLiked ? "heart-fill" : "heart"}
                isLiked={product.isLiked}
                size={24}
                onPress={() =>
                  toggleProductLikedStatus({
                    productId: product.id,
                    currentIsLiked: product.isLiked,
                  })
                }
              />
            </ImageContainer>
            <ProductContainer>
              <FlexContainer>
                {product.product_color?.map((color) => {
                  return <ProductColor key={color} color={color} />;
                })}
              </FlexContainer>

              <ProductName numberOfLines={1} ellipsizeMode="tail">
                {product.product_name}
              </ProductName>
              <ProductPrice>
                {product.product_price.toLocaleString()}
              </ProductPrice>
            </ProductContainer>
          </ProductCard>
        );
      })}
    </Wrapper>
  );
}

하지만 좋아요 버튼을 눌렀을 때 좋아요 버튼이 변경되는 것은 확인 했으나 다른 탭을 클릭한 후, 다시  홈 탭에 돌아왔을 때 좋아요 버튼이 원래대로 돌아가있는 상황을 발견하게 되었다.

 

원인 발견

트러블 슈팅1과 같은 현상으로 탭을 이동할 때 현재 react-natvie-tab-view가 현재 Index의 컴포넌트를 렌더링하게 되면서 처음 렌더링할 때의 productData를 적용하게 된 것.

상위 컴포넌트의 데이터를 전달받아 사용중이 었기때문에 현재 버튼을 누른 상품의 상태만을 바꾸는 것은 의미없는 행동이 되어버림.

 

이 문제 때문에 좋아요 버튼을 누를 때 서버에서 상품의 데이터를 가져와서 다시 적용할까 엄청 고민을 했었지만, 조금만 더 고민해보고 노력해보기로 했다.

 

해결 방법

상위 컴포넌트인 Home에서 함수를 만들어 ProductList컴포넌트에 props로 할당하면 되는 간단한 방법도 있었지만 리덕스를 활용하여 업데이트하는 방법을 사용해보고 싶었다. 

 

호기심에 해본 작업이었지만 하면서도 되게 후회했다. 좋아요 상태업데이트 하나에 너무 복잡하게 돌아간다는 느낌..?

 

ProductList 컴포넌트에서 리덕스를 활용하여 좋아요 버튼을 클릭했을 때 아이디와 좋아요 상태를 관리하고, Main 컴포넌트에서는 useSelector 훅을 사용하여 likes 상태를 구독하였다.

좋아요 버튼을 눌렀을 때 상태가 저장되게 되고, 메인 컴포넌트에서는 productInfo를 업데이트한다. 
메인 컴포넌트가 리렌더링 되면서 업데이트된 데이터 역시 하위컴포넌트에게 전달이 된다.

또한, setProductsData 함수를 호출함으로써 ProductList 컴포넌트가 새로운 데이터를 받아 렌더링하게 한다.

 

// Home.tsx

const likes = useSelector((state: LikeState) => state.likes.likes);
  
useEffect(() => {
    setProductInfo((prevProductInfo) => {
      return prevProductInfo.map((product) => {
        if (product.id === likes.productId) {
          return {
            ...product,
            isLiked: !likes.isLiked,
          };
        }
        return product;
      });
    });
}, []);
// ProductList.tsx

const toggleProductLikedStatus = ({
    productId,
    isLiked,
  }: LikesProductType) => {
    dispatch(toggleLike({ productId, isLiked }));

    setProductsData((prevProducts) => {
      return prevProducts?.map((product) => {
        if (product.id === productId) {
          const isLiked = !product.isLiked;
          return {
            ...product,
            isLiked: isLiked,
          };
        }
        return product;
      });
    });
  };
  useEffect(() => {
    setProductsData(products);
  }, [products]);

 

 

// likes reducer
  
export interface AuthState {
  likes: LikesProductType;
  loading: boolean;
  error: any;
}

interface LikesSagaAction {
  type: string;
  payload: LikesProductType;
}

const prefix = "http://로컬 IP";

// 액션 타입 정의
const PENDING = `${prefix}/PENDING`;
const SUCCESS = `${prefix}/SUCCESS`;
const FAIL = `${prefix}/FAIL`;
const TOGGLE_LIKE = `${prefix}/TOGGLE_LIKE`;

// 액션 생성 함수
const pending = () => ({ type: PENDING });
const success = (likes: LikesProductType) => ({
  type: SUCCESS,
  payload: likes,
});
const fail = (error: Error | null) => ({ type: FAIL, payload: error });

export const toggleLike = (product: LikesProductType) => ({
  type: TOGGLE_LIKE,
  payload: product,
});

// 초기 상태 정의
const initialState: AuthState = {
  likes: { productId: null, isLiked: false },
  loading: false,
  error: null,
};

// 리듀서 함수 정의
const reducer = (
  state: AuthState = initialState,
  action: Action<LikesProductType>
): AuthState => {
  switch (action.type) {
    case PENDING:
      return { ...state, loading: true };
    case SUCCESS:
      return {
        ...state,
        likes: action.payload,
        loading: false,
        error: null,
      };
    case FAIL:
      return { ...state, loading: false, error: action.payload };
    default:
      return state;
  }
};

// 사가 함수 정의
function* likesSaga(action: LikesSagaAction) {
  try {
    yield put(pending());
    yield call(updateProductLikedStatus, {
      productId: action.payload.productId,
      isLiked: !action.payload.isLiked,
    });

    // 성공 액션 디스패치
    yield put(
      success({
        productId: action.payload.productId,
        isLiked: !action.payload.isLiked,
      })
    );
  } catch (error: any) {
    yield put(fail(error));
  }
}

// 루트 사가 함수 정의
export function* callSaga() {
  yield takeEvery(TOGGLE_LIKE, likesSaga);
}

export default reducer;

 

 

느낀점

typescript와 react-native에 대한 기초개념을 공부한 이후에 처음 만들어보는 프로젝트이기도하고, redux-saga 또한 처음 공부해서 시도해보고 있다.

역시 맨땅에 헤딩을 해서 그런지 간단한 작업조차 이틀이 걸렸다(물론 쉬면서 해서 그렇지만..)

리액트 네이티브에서 map함수를 사용하면 성능이 좋지않아 권장하지 않는다는 이야기를 들었고,

대규모 데이터를 활용할때 좋은 FlatList를 활용하고자 하였지만 FlatList 또한 Scroll속성이 있어 ScrollView와 함께 사용하면 충돌이 일어난다는 사실도 알게 되었다.

이것 때문에 시간이 더 잡힌 것도 없지않아 있었지만 결국 적용을 하지 못 했다는 것에 아쉬움이 크다.

메인 홈페이지에서는 전체 ui가 스크롤 되어야하지만 FlatList는 적용하는 대상에만 스크롤이 걸리기때문에 상품의 정보를 렌더링하는 ProductList 컴포넌트에 사용이 가능한 거라 결국 메인 컴포넌트에는 사용을 하지 못했다. 

물론 잘 알지못해서 적용을 못 했을 수도 있다고 생각하지만 이것 또한 과정이라 생각하기로 했다.

 

결론: 혼자서 헤딩하는 것은 너무 힘들다

'TIL & WIL' 카테고리의 다른 글

230607 TIL - 전역 모달을 만들어보다  (0) 2023.06.07
230221_TIL  (0) 2023.02.21
230217_TIL  (2) 2023.02.18
230213_TIL  (0) 2023.02.14
230204_TIL  (1) 2023.02.04

오늘 공부한 내용

  • 스파르타 면접스터디 시작
  • 개인 과제

어려웠던 내용

면접 스터디에서는 cs에 관련된 질문들을 많이 내주시는 것 같다. 오늘의 개인과제 질문은 브라우저와 rest api에 관련된 질문이었다.

  • 웹페이지가 브라우저에 랜더링되는 과정을 설명해주세요.(클릭)
  • Restful API에 대해 설명해주세요. GET,POST 외에 알고있는 메소드와 그 기준을 설명해주세요. RESTful API 가 아닌 것들은 어떤게 있나요?(클릭)

느낀점

나와는 다르게 면접준비도 잘하고 계신 분들이었고 심지어 경력자분들도 계시는 것같아 많이 긴장되고 능력차이가 나는 것 같아 처음엔 의기소침했었지만 오늘 서울에서 대구로 내려오면서 많은 생각들을 해보곤 했다.

2주라는 짧은 시간동안 이분들에 녹아들면서 많은 것들을 배우겠노라 생각을 바꾸게 되었지만 과연 이게 잘 생각한 부분인지 아직은 잘 모르겠다.

개념에 대해서는 당연히 모르는게 많고 힘들겠지만 우선은 부딪히려고 한다. 처음부터 차근차근 부끄러워도 꼭 발전할 수 있길.

 

참고

 

'TIL & WIL' 카테고리의 다른 글

230607 TIL - 전역 모달을 만들어보다  (0) 2023.06.07
react-native 트러블 슈팅  (0) 2023.06.06
230217_TIL  (2) 2023.02.18
230213_TIL  (0) 2023.02.14
230204_TIL  (1) 2023.02.04

오늘 공부한 내용

  • mock interview 50문 공부
  • 인텔리픽 모의면접 

어려웠던 내용

  • 면접을 볼 때, 차분히 내 생각을 정리한 후 논리적으로 말하는 것이 너무 힘들었다. 당연히 완벽하게 숙지가 되지 않아서 그렇다는 사실은 알고 있다. 그럼에도 모든 질문들에 답을 하려고 최선의 노력을 했었고 멘토님께서도 긴장하지 않도록 많이 배려를 해주셨던 것 같다. 프로젝트에 관련된 질문내용들을 가장 많이 해주셨지만 그래도 가장 기억에 남았던 질문은 협업에 관련된 질문내용이었다.

            1. 팀플레이를 하시면서 이런 분과는 협업하기가 조금 까다롭다 하시는 분은 어떤 분이 있으실까요?

            2. 면접자분께서 말씀하시는 소통이란 어떤 건지 여쭤봐도 될까요?

            3. 그렇다면 면접자분과 가장 시너지가 났던 분은 어떤 분이신가요?

 

이 질문들은 멘토님께서 질문을 주셨던 것이지만 사실 내 자신이 스스로에게 주고 싶었던 질문이기도 하였거니와

혼자만의 시간을 가지면서 부끄러운 내 모습을 직면해보던 시간이 있었기때문에 

이번 기회에 질문들을 받았을 때, 나는 어떤 협업하고 싶은 개발자가 되고 싶은 것일까?에 대해 한번 더 생각해보는 시간이 되었던 것 같다.

 

그 외에 질문들에는 물론 대답을 완벽하게 했던 것은 아니였던터라 답변에 관련하여 보충할 내용도 그리고 시간도 필요한 것 같다.

모의 면접 덕분에 면접에서 받을 예상 질문, 그리고 내가 생각하기에 부족했던 점들을 정리하게 되는 시간을 보낼 수 있어서 보람찬 하루였다.

궁금한 내용 / 부족한 내용

  • 내가 면접을 본 시간은 총 30분정도 소요가 되었던 것 같다. 그 중에서 10분정도는 궁금했던 점들을 많이 물어보게 되었는데 감사하게도 멘토님께서는 괘념치말라하시며 잘받아주셔서 너무나도 감사했었다. 어떤 질문을 했는지 구체적으로 적기에는 창피한 부분들이 많아 직접적으로 쓰지는 못하겠지만, 대체적으로 신입 개발자들이 필요한 역량이나 실제 면접당시 어떤 사람을 필요로하는지, 그리고 생각을 정리해서 잘 말할 수 있는 연습방법이나 노하우에 대해서 여쭤보았던 것 같다.

느낀점

사실 처음부터 준비된 분도 계실 것이고 워낙 자기관리를 잘하신 분들도 많으셔서 나에게는 너무 부러운 능력이지만, 처음부터 생각해왔던 것처럼 그런 능력을 부러워하되 시기, 질투와 같이 다른 사람과 나를 비교하지 않을 것이라 생각하며 멘탈관리를 꾸준히 해왔었다. 

늘 그래 왔듯이 내가 부족한 점을 인지하고 더 나아갈 방향만 바라 볼 것을 오늘도 다짐한다. 또한 긍정적인 마인드가 내 주변의 사람들에게는 좋은 영향력을 주길 바란다.

'TIL & WIL' 카테고리의 다른 글

react-native 트러블 슈팅  (0) 2023.06.06
230221_TIL  (0) 2023.02.21
230213_TIL  (0) 2023.02.14
230204_TIL  (1) 2023.02.04
230203_TIL  (0) 2023.02.03

오늘 공부한 내용

  • 항해99 지원주차
  • 모의면접 세션 특강 듣기
  • 인텔리픽 관련 목터뷰 50문에 대해 적어보기(15/50)

궁금한 내용 / 부족한 내용

  • 면접 질문 리스트 중 링크드리스트에 대한 질문과 평소 많이 들어보던 CORS에 대한 질문지를 보았을 때에는 미쳐 개념에 대해 생각해보지 않았던 문제여서 그런지 답을 어떻게 적어야할 지 정말 막막했던 것 같다. 하지만 조금이라도 개념에 대해 알고 있는 부분에 대해서는 스스로 아는 부분을 적은 후 질문에 대한 답을 구글링을 통해 정리를 하여 현재 내가 몰랐거나 부족했던 개념을 채웠었고, 또 다시 같은 질문에 다른 분은 어떤 방식으로 해답을 하셨는지 비교하면서 내가 보충해야 했던 개념들을 다시 정리하여 이해하는 방식으로 진행했다.

느낀점

오늘 오후 3시 면접에 관한 세션에서는 면접 뽀개기라는 타이틀에 맞게 신입 개발자들이 면접을 할때에 겪는 일들과 마인드의 자세에 대한 주제로 진행이 되었다. 진행자이신 이동현 팀장님께서는 모든 분들에게 자신은 어떠한 신입 개발자인지 먼저 생각해보라는 조언을 해주셨고 면접에 우선 많은 도전을 해보아야 한다라고 말씀하시며 실패라는 경험을 소중하게 어떻게 대해야하는 지, 개선해 나아가야할 방향은 어떻게 잡아야하는지에 대한 내용을 위주로 잘 설명해주셔서 많은 도움이 되었다. 

실패에 대한 두려움을 우선 없애야 한다는 점. 그리고 절대적인 시도횟수가 가장 중요하지만,  현명하게 그리고 효율적으로 내가 이상황을 이용하는게 키포인트라는 생각을 해보게 되었다.

항해를 수료한 이후에도 시간을 효율적으로 사용해야 할 지 미리 계획을 세워보며 하루를 마무리 해본다.

'TIL & WIL' 카테고리의 다른 글

230221_TIL  (0) 2023.02.21
230217_TIL  (2) 2023.02.18
230204_TIL  (1) 2023.02.04
230203_TIL  (0) 2023.02.03
230202_TIL  (0) 2023.02.03

오늘 공부한 내용

  • 항해 99 실전프로젝트 
  • 김선우 멘토님의 기술멘토링 시간 

궁금한 내용 / 부족한 내용

 

멘토링 답변 관련 내용

프로젝트에 사용된 기술에 대하여 사전에 전달을 받고 멘토님께서 질문하는 시간이 있었다. 

멘토님께서 질문하신 내용은 리액트 쿼리와 리프레시 토큰에 관한 질문을 해주셨다. 리액트 쿼리 > 무한스크롤의 사용에 대한 질문은 설득을 잘 해서 넘어가나 싶었지만 리프레시 토큰에 대한 답변은 제대로 하지 못했다.

 

질문의 내용은 이렇다.

리프레시 토큰을 사용하셨던데, 리프레시 토큰을 어디에다가 저장하셨어요?   / 쿠키에 저장한 이유는요?  / 그렇다면 리프레시 토큰은 서버에도 저장이 되는 걸 아는데 굳이 프론트에서 저장하는 이유는 어떤 것인가요?  / 쿠키에 저장 된 리프레시 토큰도 탈취될 수 있다는 이야기인데 그렇다면 탈취된 상황에서 똑같이 토큰을 재발급받아 버릴 수 있지 않나요? / 그렇다면 서버측에서 그 유저를 로그아웃시키는 것은 어떻게 하나요?

 

잘 대답을 해나가던 중 이 부분은 정말 생각도 못했던 방식이었다. 왜 리프레시 토큰을 프론트에 저장을 할까?

원래 알던 단순한 내용으로는 액세스토큰을 저장하고 있다가 만료가 되면 리프레시 토큰으로 재발급을 받기위해서 사용을 하는 것이고, 그것을 위해 쿠키에 넣은 것이였는데, 왜 프론트에 저장을 한것인가에 대한 질문은 생각지 못했다. 

 

아니 조금 더 말하자면 그렇게 단순한 질문 일 것 같지가 않아서 당황스러웠다. 당연히 만료된 토큰을 재발급 받기 위해서 리프레시 토큰을 저장했다는 원하시진 않으실 것 같아서 대답을 하지 못한 것.

 

우선은 리프레시 토큰을 서버가 아닌 프론트에 저장을 하는 이유는 서버의 부하를 막기 위해서라고 하셨다.

접속한 유저들이 많으면 많아질수록 백엔드에 리프레시 토큰을 저장하는 방법은 서버측에 부담을 줄 수 있기 때문에 프론트에 저장을 하여 만료되었을 경우 만료된 토큰을 새로 발급받을 수 있게 한다는 것.

 

그리고 리프레시 토큰이 탈취되었을 경우 서버측에서 로그아웃을 시킬 수 있다는 내용을 조금 더 정확하게 알아 내셔서 면접관을 설득을 해주셔야 한다는 답변까지 받게 되었다.

정말정말 신기하게도 정확하게 잘 알지 못한 상태라는 것을 멘토님께서는 잘 알고 계셨고 그 부분을 건들여서 내가 무엇을 모르고 있는지, 놓치고 있는지, 어떤 것을 알아서 설득을 해야하는지에 대해 차분히 설명을 해주셔서 너무나도 나에게 도움이 되었던 시간이었다.

그리고 항상 왜? 라는 생각을 해보아야겠다 라는 생각도 해보게 되었다.

느낀점

음~ 개발자는 아무나 될 수 있는 게 아니구나하는 생각을 해본다. 개발자를 흉내내는 사람은 될 수 있어도 진짜 개발자가 되기 위해서는 많은 시간을 거쳐 생각을 하고 행동할 수 있어야 하는구나하며 생각해보게 되었다. 

유튜브에 가끔씩 개발자가 생각해야 하는 것들 이라던가 어떤 것들을 생각하는 개발자가 되어야한다는 내용의 동영상들을 그냥 썸네일 이미지만 보고 지나쳤을 때가 있었다. 이제서야 그런 기본적인 마인드를 세팅하는 것이 중요한 것이구나라는 걸 이해하게 되는 날이였던 것 같다.

'TIL & WIL' 카테고리의 다른 글

230217_TIL  (2) 2023.02.18
230213_TIL  (0) 2023.02.14
230203_TIL  (0) 2023.02.03
230202_TIL  (0) 2023.02.03
230201_TIL  (0) 2023.02.02

오늘 공부한 내용

  • 항해 99 실전프로젝트
  • 오류 및 개선사항 코드 수정 중

궁금한 내용 / 부족한 내용

모달을 클릭 했을 때 뒤에 생기는 스크롤을 삭제하고 싶었다.  기존에 사용 했던 코드는 

const useModal = () => {
  const [modal, setModal] = useState(false);
  const handler = () => {
    setModal(!modal);
    modal
     ? (document.body.style.overflowY = 'visible')
      : (document.body.style.overflowY = 'hidden');
  };
  return [modal, handler];
};

이러했다. 

하지만 모달 팝업에 관련된 내용을 찾아보던 중 cssText을 권유하라는 글을 보고 수정을 하게 되었다. 그 포스트에 관련된 내용을 빌려 말하자면 cssText 쓰는 이유는 style 여러번 접근하면 횟수만큼 reflow 발생하게 된다. cssText 이용하면 1번만 계산하기 때문에 이렇게 js css 건드릴 경우 퍼포먼스를 위해 필수로 해주는 것이 좋다고 한다.

 

modal
      ? (document.body.style.overflowY = 'visible')
      : (document.body.style.overflowY = 'hidden');

 

하지만 이유를 모르겠지만 한번씩 가끔 스크롤이 없어진 상태로 페이지가 렌더링 되는 상황이 발생하고 있다. 아마 이 'hidden' 속성때문이라고 파악하고 확인을 했다. 어떻게 렌더링을 하는 과정에서 모달을 열지도 않았는데 스크롤 hidden이 발생이 되는지 아직 감이 잡히지 않아 난감한 상황이다.

 

느낀점

프로젝트 발표에 관한 발제를 듣는 날이라서 그런지 뭔가 기분이 싱숭생숭하기도 하고 다시 조급해지는 날이였다. 끝이 코 앞으로 다가와 반가운 날이기는 하지만 그 반대로 새로운 환경으로 다시 적응해야 하는 의미이기도 하기에 호기심 반 두려움 반으로 생각이 드는 날었다. 

열심히 준비하는 팀원들을 위해서라도 끝까지 최선을 다하길!

'TIL & WIL' 카테고리의 다른 글

230213_TIL  (0) 2023.02.14
230204_TIL  (1) 2023.02.04
230202_TIL  (0) 2023.02.03
230201_TIL  (0) 2023.02.02
230130_TIL  (0) 2023.01.30

오늘 공부한 내용

  • 항해 99 실전프로젝트  
  • 불편사항 및 오류 사항 해결

느낀점

  • 불편사항 개선은 정말 해도해도 끝이 없다는 것을 느낀다..  시간 상 불편사항이나 오류사항들 위주로 수정을 하고 추가적인 기능들을 그 이후로 미루게 되었다. 현재 sse관련 하여 백엔드에서 기능 구현에 문제를 겪고 있는 상황과 리프레쉬 토큰문제로 보이는 에러 사항을 수정하고 나면 숨이 트이지 않을까 생각 중이다. 유지보수 하는 기간도 역시 쉽지 않구나 생각이 든다.

'TIL & WIL' 카테고리의 다른 글

230204_TIL  (1) 2023.02.04
230203_TIL  (0) 2023.02.03
230201_TIL  (0) 2023.02.02
230130_TIL  (0) 2023.01.30
230129_TIL  (0) 2023.01.29

+ Recent posts