홈페이지 전역에서 스크롤 높이에 따라 헤더의 색상을 다르게 보여주는 기능을 사용하고 싶었다. 전역 상태관리를 위해 Redux/toolkit을 사용하면서 오늘 다시 한번 정리하는 글!
headerSlice에서는 show 라는 불리언 속성에 따라 show가 false일 때는 원래 흰색 글씨의 헤더, true일 때는(스크롤 높이가 일정길이 이상 내려갔을 때) 글씨가 검정색으로 변하게 할 것이다.
//headerSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
export interface HeaderState {
show: boolean;
}
const initialState: HeaderState = {
show: false,
};
const headerSlice = createSlice({
name: 'header',
initialState,
reducers: {
setShow: (state, action: PayloadAction<boolean>) => {
state.show = action.payload;
},
},
});
export const { setShow } = headerSlice.actions;
export default headerSlice.reducer;
reducers에서 setShow 라는 액션을 정의한다. PayloadAction을 사용하고, boolean 타입을 받는다. setShow 액션이 실행될 때, state 객체의 show 속성이 action.payload 값으로 설정된다!
//store.ts
import { configureStore } from '@reduxjs/toolkit';
import headerReducer from './slice/headerSlice';
const store = configureStore({
reducer: {
header: headerReducer,
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;
타입스크립트로 redux/toolkit을 작성해보기는 처음이라서, Rootstate를 작성해주지 않아 애를 먹었다.
앞으로 Typescript로 redux/toolkit을 사용할 경우, store는 그냥 아래에 있는 걸 template으로 작성하면 된다.
import { configureStore } from '@reduxjs/toolkit'
export const store = configureStore({
reducer: {},
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
위에서 export type RootState = ReturnType<typeof store.getState>을 작성한 것은 RootState와 Dispatch의 타입을
reducer에 state slice를 추가한 store의 타입을 추론해 지정한 것이다.
- 앱 전체를 Provider로 감싸주기
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Global, Theme } from '@emotion/react';
import GlobalStyle from './styles/globalStyle';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { Provider } from 'react-redux';
import store from './store/store';
oauth/google';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<Provider store={store}>
{' '}
<ThemeProvider theme={theme}>
<Global styles={GlobalStyle} />
<App />{' '}
</ThemeProvider>
</Provider>
</React.StrictMode>
);
- 사용할 컴포넌트에서 headerSlice 가져다 쓰기
import { StyledHeader, LogoWrapper } from './style';
import Logo from '../Logo';
import Nav from '../Nav';
import { useEffect } from 'react';
import { setShow, HeaderState } from '@src/store/slice/headerSlice';
import { useDispatch, useSelector } from 'react-redux';
//redux 스토어와 상호작용하기 위해 useDispatch, useSelector 훅 가져오기!
function Header() {
const dispatch = useDispatch();
const show = useSelector(
(state: { header: HeaderState }) => state.header.show
);
//headerSlice에서 show 속성 값 가져오기
useEffect(() => {
const handleScroll = () => {
if (window.scrollY > 114) {
dispatch(setShow(true));
} else {
dispatch(setShow(false));
}
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, [dispatch]);
return (
<StyledHeader show={show}>
<LogoWrapper>
<Logo show={show} />
</LogoWrapper>
<Nav show={show} />
</StyledHeader>
);
}
export default Header;
확실히 그냥 redux만 쓸때보다는 RTK를 쓰는 것이 훨씬 코드 읽기나 사용법도 간단한 것 같다!