아래 포스팅은 내가 만든 프로젝트 코드를 바탕으로 설명 한다.
yarn add redux react-redux
리액트 파일을 생성후 위와 같이 redux패키지를 설치한다.
외부의 데이터와 연동하고 싶다면 thunk 까지 다운 받는다
yarn add redux-thunk
다음으로 index.js 파일에서 아래와 같이 세팅 하는데,
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import store from "./redux/configStore";
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById("root")
);
reportWebVitals();
redux를 Provider로 import 한 후에, render 부분에서
<Provider store={store}> </Provider>
위의 태그로 감싸면 된다.
다음으로 action, actionCreator, reducer 를 담은 파일
word.js 파일의 코드를 보면
import {
collection,
doc,
getDoc,
getDocs,
addDoc,
deleteDoc,
} from "firebase/firestore";
import { db } from "../../firebase";
// 액션
const LOAD = "words/LOAD";
const ADD = "words/ADD";
const initialState = {
words: [],
};
// 액션 생성 함수
export const loadWords = (words_list) => {
return { type: LOAD, words_list };
};
export const addWords = (words_list) => {
return { type: ADD, words_list };
};
// 미들웨어
export const loadWordsFB = () => {
return async function (dispatch) {
const words_data = await getDocs(collection(db, "words"));
let words_list = [];
words_data.forEach((words) => {
words_list.push({ ...words.data() });
});
dispatch(loadWords(words_list));
};
};
export const addWordsFB = (words_list) => {
return async function (dispatch) {
console.log(words_list);
await addDoc(collection(db, "words"), words_list);
// dispatch(addWords(words_list))
};
};
//리듀서
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case "words/LOAD": {
return { ...state, words: action.words_list };
}
case "words/ADD": {
const new_words = [...state.words, action.words_list];
return { ...state, words: new_words };
}
default:
return state;
}
}
위의 코드의 주석대로 기능을 묶어서 작성한다.
위의 코드는 단순히 input 값을 Add 하고, Load 하는 기능을 구현했다.
그리고 중간의 미들웨어는 FIrebase와 연동하기 위한 작업이다.
파이어베이스와 연동하기 위해서는 firebase.js 라는 파일을 만들고, 그 안에 Firebase 에서 제공하는 연동 코드를 붙여넣으면 된다.
다음 작업으로는 export default 한 리듀서를 받아와 묶어서(rootReducer)
store를 만드는 작업이 남았다. 아래의 코드는 configStore.js라는 파일이다.
// Store의 기본 설정이라고 생각하면됨, combineReducers은 리듀서를 묶어주는 역할을 한다.
// Store를 만들기 위해 createStore가 필요하다.
import { createStore, combineReducers, applyMiddleware } from "redux";
import thunk from "redux-thunk";
// 리듀서를 가져온다.
import word from "./modules/word";
const middlewares = [thunk];
// 리듀서를 다 묶은 것을 rootReducer라고 한다.
const rootReducer = combineReducers({ word });
const enhancer = applyMiddleware(...middlewares);
// rootReducer가지고 store를 만들어준다.
const store = createStore(rootReducer, enhancer);
export default store;
Add.js 파일은 input 안에 값을 넣고 Button 을 누르면 그 값이 Firebase 에 저장 되도록 하였다.
그리고 word.js 에서 생성했던 미들웨어 함수 addWordFB를 import 해와서 Button 클릭시 input에 입력된 값을 전달하도록 한다!! (dispatch 이용)
import React from "react";
import { useHistory } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { addWords, addWordsFB } from "./redux/modules/word";
const history = useHistory();
const dispatch = useDispatch();
const word_ref = React.useRef(null);
const explanation_ref = React.useRef(null);
const ex_ref = React.useRef(null);
//input 태그 생략
.// 전체 코드 아님 주의
.
.
<button
onClick={() => {
dispatch(
addWordsFB({
word: word_ref.current.value,
explanation: explanation_ref.current.value,
ex: ex_ref.current.value,
})
);
history.push("/");
}}
history.push를 통해 url을 변경한다.(라우팅)
Home.js 파일은 파이어베이스에 저장되어있는 데이터들을 불러와 화면에 나타내주기 위한 파일이다!
이 파일은 전체 코드를 붙여봤다. 이유는 다양한 기능을 동시에 설명하고 싶어서..
아래의 코드에서 쓰인 기능 중 styled-componets 는 react 에서 css를 좀 더 편하게 사용할 수 있도록 도와준다.
styled components 코드는 맨 하단의 const로 변수를 만들어 그것을 태그 이름으로 하도록 할 수 있다.
import React from "react";
import styled from "styled-components";
import { useSelector, useDispatch } from "react-redux";
import { useParams } from "react-router";
import {
border,
width,
} from "../../SPARTA_REACT/bucket_list/node_modules/@mui/system";
import { useHistory } from "react-router-dom";
import { loadWordsFB } from "./redux/modules/word";
const Home = ({ list }) => {
const word_list = useSelector((state) => state.word.word_list);
const dispatch = useDispatch();
console.log(word_list);
const history = useHistory();
React.useEffect(() => {
dispatch(loadWordsFB());
}, []);
const _word_data = useSelector((state) => state.word.words);
console.log(_word_data);
return (
<div>
{_word_data.map((dictionary, index) => {
return (
<Cards key={index}>
<Words>
<p>단어</p>
<p style={{ border: "1px solid #ddd" }}>{dictionary.word}</p>
<p>설명</p>
<p style={{ border: "1px solid #ddd" }}>
{dictionary.explanation}
</p>
<p>예시</p>
<p style={{ border: "1px solid #ddd", color: "lightsteelblue" }}>
{dictionary.ex}
</p>
</Words>
</Cards>
);
})}
<AddButton
onClick={() => {
history.push("/add");
}}
>
+
</AddButton>
</div>
);
};
const AddButton = styled.button`
width: 60px;
height: 60px;
background-color: #a673ff;
border-radius: 100px;
border: 0px;
color: #fff;
font-size: 83px;
position: fixed;
display: flex;
align-items: center;
right: 8%;
bottom: 15%;
`;
const Words = styled.div`
width: 200px;
background-color: lightyellow;
border: 1px solid #ddd;
padding: 10px;
height: 250px;
margin: 0;
margin: 20px;
`;
const Cards = styled.div`
margin-top: 15px;
display: flex;
justify-content: center;
align-items: center;
float: left;
`;
export default Home;
위의 코드에서 잘 보면 아래의 dispatch 를 통해 파이어베이스의 데이터를 호출하는 함수 loadWordsFB 함수를 word.js 에서 불러와 일으킨다.
React.useEffect(() => {
dispatch(loadWordsFB());
}, []);
다음으로 아래의 코드를 통해 변수에 그 값들을 저장한다.
const _word_data = useSelector((state) => state.word.words);
위의 화살표 뒤의 코드 sate.word(js파일 이름).words(word.js의 리듀서에서 return 한 리스트 이름)
이제 불러온 값들을 아래와 같이 map을 이용해 index별로 받아와 값을 나타낸다.
{_word_data.map((dictionary, index) => {
return (
<Cards key={index}>
<Words>
<p>단어</p>
<p style={{ border: "1px solid #ddd" }}>{dictionary.word}</p>
<p>설명</p>
<p style={{ border: "1px solid #ddd" }}>
{dictionary.explanation}
</p>
<p>예시</p>
<p style={{ border: "1px solid #ddd", color: "lightsteelblue" }}>
{dictionary.ex}
</p>
</Words>
</Cards>
);
})}
위와 같은 과정들을 거치고난 결과 화면
단어장 완성!!