src/components/Menu/ThemeMenu.jsx
firebase : onChildAdded(쿼리, 콜백, 취소콜백)
특정 위치에서 데이터 변경 사항을 수신합니다. 이것은 데이터베이스에서 데이터를 읽는 기본 방법입니다. 콜백은 초기 데이터에 대해 그리고 데이터가 변경될 때마다 다시 트리거됩니다. 반환된 구독 취소 콜백을 호출하여 업데이트 수신을 중지합니다. 자세한 내용 은 웹에서 데이터 검색 을 참조하십시오. onChildAdded
이벤트는 이 위치의 각 초기 자식에 대해 한 번 트리거되고 새 자식이 추가될 때마다 다시 트리거됩니다. 콜백에 전달된 DataSnapshot
은 관련 자식에 대한 데이터를 반영합니다. 정렬을 위해 정렬 순서에 따라 이전 형제 자식의 키를 포함하는 문자열인 두 번째 인수가 전달되거나 첫 번째 자식인 경우 null
이 전달됩니다.
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
List,
ListItem,
ListItemIcon,
Stack,
} from '@mui/material'
import React, { useCallback, useEffect, useState } from 'react'
import PaletteIcon from '@mui/icons-material/Palette'
import { HexColorPicker } from 'react-colorful'
import '../../firebase'
import {
child,
getDatabase,
onChildAdded,
push,
ref,
update,
} from 'firebase/database'
import { useDispatch, useSelector } from 'react-redux'
import { setTheme } from '../../store/themeReducer'
export default function ThemeMenu() {
// 유저 정보 가져오기
const { user } = useSelector(state => state)
// dispatch
const dispatch = useDispatch()
// 테마 모달
const [showThemeModal, setShowThemeModal] = useState(false)
// 메인 테마 색상
const [mainTheme, setMainTheme] = useState('#fffff')
// 서브 테마 색상
const [subTheme, setSubTheme] = useState('#fffff')
// 유저 테마 배열
const [userTheme, setUserTheme] = useState([])
// 모달 열기
const handleClickOpen = useCallback(() => {
setShowThemeModal(true)
}, [])
// 모달 닫기
const handleClickClose = useCallback(() => {
setShowThemeModal(false)
}, [])
// 메인 테마 바꾸기
const handleChangeMain = useCallback(color => {
setMainTheme(color)
}, [])
// 서브 테마 바꾸기
const handleChangeSub = useCallback(color => {
setSubTheme(color)
}, [])
// 테마 저장하기
const handleSaveTheme = useCallback(async () => {
// 유저 정보 없을 경우 방어
if (!user.currentUser?.uid) return
try {
const db = getDatabase() // 데이터베이스 가져오기
// 키 생성
const key = push(
child(ref(db), '/users/' + user.currentUser.uid + '/theme')
).key
// 새로운테마 생성
const newTheme = { mainTheme, subTheme }
// firebase 데이터에 업데이트하기
const updates = {}
updates['/users/' + user.currentUser.uid + '/theme/' + key] = newTheme
await update(ref(db), updates)
handleClickClose()
} catch (error) {
console.error(error)
handleClickClose()
}
}, [mainTheme, subTheme, user.currentUser?.uid, handleClickClose])
// 생성한 전체 테마 배열 만들기
useEffect(() => {
if (!user.currentUser?.uid) return
const db = getDatabase()
const themeRef = ref(db, 'users/' + user.currentUser.uid + '/theme')
const unsubscribe = onChildAdded(themeRef, snap => {
setUserTheme(themeArr => [snap.val(), ...themeArr])
})
return () => {
setUserTheme([])
unsubscribe?.()
}
}, [user.currentUser.uid])
return (
<>
<List sx={{ overflow: 'auto', width: 60, backgroundColor: '#150c16' }}>
<ListItem button onClick={handleClickOpen}>
<ListItemIcon sx={{ color: 'white' }}>
<PaletteIcon />
</ListItemIcon>
</ListItem>
{userTheme.map(theme => (
<ListItem>
<div
className="theme-box"
onClick={() =>
dispatch(setTheme(theme.mainTheme, theme.subTheme))
}
>
<div
className="theme-main"
style={{ backgroundColor: theme.mainTheme }}
></div>
<div
className="theme-sub"
style={{ backgroundColor: theme.subTheme }}
></div>
</div>
</ListItem>
))}
</List>
<Dialog open={showThemeModal} onClose={handleClickClose}>
<DialogTitle>테마 색상 선택</DialogTitle>
<DialogContent>
<Stack direction="row" spacing={2}>
<div>
Main
<HexColorPicker color={mainTheme} onChange={handleChangeMain} />
</div>
<div>
Sub
<HexColorPicker color={subTheme} onChange={handleChangeSub} />
</div>
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={handleClickClose}>취소</Button>
<Button onClick={handleSaveTheme}>테마 저장</Button>
</DialogActions>
</Dialog>
</>
)
}
const SET_THEME = 'SET_THEME'
export const setTheme = (mainTheme, subTheme) => ({
type: SET_THEME,
mainTheme,
subTheme,
})
const initialState = { mainTheme: '#4c3c4c', subTheme: '#eee' }
const themeReducer = (state = initialState, action) => {
switch (action.type) {
case SET_THEME:
return {
mainTheme: action.mainTheme,
subTheme: action.subTheme,
}
default:
return state
}
}
export default themeReducer
import { combineReducers } from 'redux'
import userReducer from './userReducer'
import channelReducer from './channelReducer'
import themeReducer from './themeReducer'
const rootReducer = combineReducers({
user: userReducer,
channel: channelReducer,
theme: themeReducer,
})
export default rootReducer
Box컴포넌트의 backgrounColor를 subtheme로 변경
ThemeMenu.jsx를 임포트해줍니다.