예전에 스프린트로 리액트의 useState를 활용해서 탭을 구현한 적이 있다. 그래서 이번에는 리덕스를 활용하여 탭을 구현하고자 했다.
클릭 이벤트가 발생한 li 요소에 selected라는 클래스네임을 할당하여 css가 입혀지게 하고 싶었다.
const initialState = {
tab: 0,
isOn: null,
};
reducers: {
activeTab: (state, action) => {
state.tab = action.payload;
state.isOn = true;
},
},
<S.Li key={idx} onClick={() => dispatch(activeTab(idx))} className={isOn ? 'selected' : ''}>
위와 같이 코드를 작성했지만 결과는 내가 원하던 대로 나오지 않았다. 클릭하면 selected class가 잘 들어가지만 다른 탭을 클릭한 후에는 기존의 selected가 사라질 줄 알았는데 사라지지 않았다.
isOn을 배열의 형테로 만들어주었다. 초기값으로 첫 번째 탭이 선택된 상태로 설정하고 map을 사용하여 선택된 탭에는 true, 선택되지 않은 탭에는 null 값을 부여해주었다. isOn 값을 배열로 관리하여 각 탭에 true 또는 null 값을 부여하고 activeTab reducer 함수에서는 선택된 탭에는 true 값을, 선택되지 않은 탭에는 null 값을 부여하도록 구현했다.
const initialState = {
tab: 0,
isOn: [true, null, null],
};
activeTab: (state, action) => {
state.tab = action.payload;
state.isOn = state.isOn.map((_, index) => index === action.payload ? true : null);
},
},
<S.Li key={idx} onClick={() => dispatch(activeTab(idx))} className={isOn[idx] ? 'selected' : ''}>
const {id} = useParams();
const data = useFetch(`/hairshop/${id}`);
위와 같은 코드로 useFetch 커스텀훅으로 get요청을 통해 받아온 데이터를 data라는 변수에 할당하였고, 콘솔로그로 확인해보니 처음에 undefined가 뜬 후 이후에 데이터가 들어왔다. 이 때문인지 data에 string 메서드를 사용하려고 하면 에러가 떴다.
useFetch hook이 비동기적으로 데이터를 가져오는 작업을 수행하고, 그 결과는 data 변수에 할당되는데 데이터를 가져오는 작업이 완료되기 전에 console.log가 실행되면, data 변수는 아직 데이터가 할당되기 전에 undefined로 설정되어 있다.
그래서 useFetch hook에 로딩중이라는 컴포넌트를 띄우는 로직을 추가하였다.
useEffect(() => {
if (window) window.scrollTo(0, 0);
dispatch(setLoading(true));
API.get(url)
.then((res) => {
setData(res.data);
})
.catch((err) => {
console.log(err);
})
.finally(() => {
dispatch(setLoading(false));
});
}, [url, dispatch]);
return data;
}
axios로 값을 가져오기전 로딩 상태를 true, 값을 가져온 후에는 false 바꿔주었고 상태는 리덕스로 관리하였다. 하지만 여전히 string 메서드를 사용하려고 하면 같은 에러가 나타났다.
아무래도 data가 초기값인 [] 때문에 string 메서드가 사용이 되지 않는 것 같았다. 그래서 삼항연산자를 사용하여 undefined가 아닐 때만 메서드를 적용하게끔 조건을 걸어주었더니 잘 적용됐다.
{data.like !== undefined ? data.like.toLocaleString() : data.like}