Skip to content

Commit

Permalink
feat(redux): React hooks을 Redux로 교체
Browse files Browse the repository at this point in the history
  • Loading branch information
27Lia committed Aug 15, 2023
1 parent 5a3bc38 commit 9e02410
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 56 deletions.
45 changes: 41 additions & 4 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"react-redux": "^8.1.2",
"react-router-dom": "^6.14.2",
"react-scripts": "5.0.1",
"redux": "^4.1.2",
"styled-components": "^6.0.7",
"web-vitals": "^2.1.4"
},
Expand Down
5 changes: 3 additions & 2 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import './App.css';
import AskQuestionPage from './pages/AskQuestionPage';

import LoginPage from './pages/LoginPage';
// import LoginPage from './pages/LoginPage';

function App() {
return (
<div className="App">
<LoginPage />
<AskQuestionPage />
</div>
);
}
Expand Down
15 changes: 11 additions & 4 deletions client/src/components/Editor5.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import { styled } from 'styled-components';
import PropTypes from 'prop-types';
import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
// import { useState } from 'react';

// ========== styled-components ==========
const StyledEditor = styled.div`
max-width: 800px;
background-color: #ffffff;
Expand Down Expand Up @@ -50,15 +52,20 @@ function Editor5({
handleButtonClick,
editorRef,
}) {
const [editorContent, setEditorContent] = useState(''); // 텍스트 내용을 상태로 관리
const dispatch = useDispatch();

const editorContent = useSelector((state) => ({
editorContent: state.editorContent,
}));

const handleEditorChange = (event, editor) => {
const data = editor.getData();
setEditorContent(data); // 텍스트 내용 업데이트
dispatch({ type: 'SET_EDITOR_CONTENT', payload: data });
};

// 처음 글자입력시 <p> 태그까지 글자로 인식하여 8부터 시작함 때문에 length를 26으로 설정
const isButtonDisabled = editorContent.length < 26;
// editorContent가 객체 형태라서 editorContent.editorContent.length
const isButtonDisabled = editorContent.editorContent.length < 26;
return (
<StyledEditor isButtonDisabled={isButtonDisabled}>
<div className="editor-container">
Expand Down
10 changes: 7 additions & 3 deletions client/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import store from './store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
);

// If you want to start measuring performance in your app, pass a function
Expand Down
117 changes: 74 additions & 43 deletions client/src/pages/AskQuestionPage.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { styled } from 'styled-components';
import Editor5 from '../components/Editor5';
import { useState, useRef } from 'react';
import { useRef } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import QuestionPageDropdown from '../components/QuestionPageDropdown';
import Header from '../components/Header';
import Footer from '../components/Footer';
// import Header from '../components/Header';
// import Footer from '../components/Footer';

const StyleAskPage = styled.div`
background-color: #f8f9f9;
Expand Down Expand Up @@ -139,81 +140,113 @@ const StyleAskPage = styled.div`
`;

function AskQuestionPage() {
const [isChecked, SetIsChecked] = useState(false);

const handleCheckboxChange = (event) => {
const checkedValue = event.target.checked;
SetIsChecked(checkedValue); // 체크박스 상태 업데이트
};

const isButtonDisabled = !isChecked;

const [checkContainerVisible, setCheckContainerVisible] = useState(false);

const [titleButtonVisible, setTitleButtonVisible] = useState(true);
const [editorButtonVisible, setEditorButtonVisible] = useState(false);
const [editor2ButtonVisible, setEditor2ButtonVisible] = useState(false);

const [tagButtonVisible, setTagButtonVisible] = useState(false);
const [reviewButtonVisible, setReviewButtonVisible] = useState(false);

const editorRef = useRef(null);
const editor2Ref = useRef(null);
const TagRef = useRef(null);

const handleTitleButtonClick = () => {
setTitleButtonVisible(false);
setEditorButtonVisible(true);
// 리덕스 스토어에 액션을 디스패치하여 상태를 업데이트 하는 dispatch함수
const dispatch = useDispatch();

const {
checkContainerVisible,
isChecked,
titleButtonVisible,
editorButtonVisible,
editor2ButtonVisible,
tagButtonVisible,
reviewButtonVisible,
isDropdownOpen,
} = useSelector((state) => ({
// 리덕스 스토어에서 상태값을 가져옴
checkContainerVisible: state.checkContainerVisible,
isChecked: state.isChecked,
titleButtonVisible: state.titleButtonVisible,
tagButtonVisible: state.tagButtonVisible,
reviewButtonVisible: state.reviewButtonVisible,
editorButtonVisible: state.editorButtonVisible,
editor2ButtonVisible: state.editor2ButtonVisible,
isDropdownOpen: state.isDropdownOpen,
}));

// isChecked 상태의 반전 값을 가짐
const isButtonDisabled = !isChecked;

// 첫 번째 에디터에 포커스 설정
// ========== 핸들러 함수내 액션을 디스패치하여 Redux 상태를 업데이트하는 부분입니다. ==========

// 제목 버튼 클릭 핸들러
const handleTitleButtonClick = () => {
// titleButtonVisible 상태를 숨김(false)으로 변경
dispatch({ type: 'SET_TITLE_BUTTON_VISIBLE', payload: false });
// editorButtonVisible 상태를 표시(true)로 변경
dispatch({ type: 'SET_EDITOR_BUTTON_VISIBLE', payload: true });
// 만약 editorRef가 현재 존재하고 에디터 인스턴스가 있는 경우,
// 첫 번째 에디터의 인스턴스에 포커스를 설정
if (editorRef.current && editorRef.current.editor) {
const editorInstance = editorRef.current.editor;
editorInstance.focus();
}
};

// 첫 번째 에디터 버튼 클릭 핸들러
const handleEditorButtonClick = () => {
setEditorButtonVisible(false);
setEditor2ButtonVisible(true);
// 두 번째 에디터에 포커스 설정
// editorButtonVisible 상태를 숨김(false)으로 변경
dispatch({ type: 'SET_EDITOR_BUTTON_VISIBLE', payload: false });
// editor2ButtonVisible 상태를 표시(true)로 변경
dispatch({ type: 'SET_EDITOR2_BUTTON_VISIBLE', payload: true });
// 만약 editor2Ref가 현재 존재하고 에디터 인스턴스가 있는 경우,
// 두 번째 에디터의 인스턴스에 포커스를 설정
if (editor2Ref.current && editor2Ref.current.editor) {
const editorInstance = editor2Ref.current.editor;
editorInstance.focus();
}
};

// 두 번째 에디터 버튼 클릭 핸들러
const handleEditor2ButtonClick = () => {
setEditor2ButtonVisible(false);
setTagButtonVisible(true);
// 태그에 포커스 설정
// editor2ButtonVisible 상태를 숨김(false)으로 변경
dispatch({ type: 'SET_EDITOR2_BUTTON_VISIBLE', payload: false });
// tagButtonVisible 상태를 표시(true)로 변경
dispatch({ type: 'SET_TAG_BUTTON_VISIBLE', payload: true });
// 만약 TagRef가 현재 존재하면 (태그 입력란이 마운트되어 있으면),해당 태그 인풋에 포커스를 설정
if (TagRef.current) {
TagRef.current.focus();
}
};

// 태그 버튼 클릭 핸들러
const handleTagButtonClick = () => {
setTagButtonVisible(false);
setReviewButtonVisible(true);
setCheckContainerVisible(true);
// tagButtonVisible 상태를 숨김(false)으로 변경
dispatch({ type: 'SET_TAG_BUTTON_VISIBLE', payload: false });
// checkContainerVisible 상태를 표시(true)로 변경
dispatch({ type: 'SET_CHECK_CONTAINER_VISIBLE', payload: true });
// reviewButtonVisible 상태를 표시(true)로 변경
dispatch({ type: 'SET_REVIEW_BUTTON_VISIBLE', payload: true });
};

// 질문 검토 버튼 클릭 핸들러
const handleReviewButtonClick = () => {
setReviewButtonVisible(false);
setCheckContainerVisible(false);
// reviewButtonVisible 상태를 숨김(false)으로 변경
dispatch({ type: 'SET_REVIEW_BUTTON_VISIBLE', payload: false });
//checkContainerVisible 상태를 숨김(false)으로 변경
dispatch({ type: 'SET_CHECK_CONTAINER_VISIBLE', payload: false });
};

// 드롭다운 상태를 관리하는 상태 변수
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
// 체크박스 변경 핸들러 함수
const handleCheckboxChange = (event) => {
// 체크박스의 선택 여부를 가져옴
const checkedValue = event.target.checked;
// 리덕스 스토어에 액션을 디스패치하여 isChecked 상태를 업데이트함
dispatch({ type: 'SET_IS_CHECKED', payload: checkedValue });
};

// 드롭다운 토글 함수
const handleDropdownToggle = () => {
setIsDropdownOpen(!isDropdownOpen);
// isDropdownOpen 상태를 토글함
dispatch({ type: 'SET_IS_DROPDOWN_OPEN' });
};

return (
<StyleAskPage isButtonDisabled={isButtonDisabled}>
<Header />

{/* header 넣을자리 */}
<div className="inner">
{/* 질문 헤더 부분 */}
Expand Down Expand Up @@ -331,7 +364,6 @@ function AskQuestionPage() {
isOpen={isDropdownOpen}
onToggle={handleDropdownToggle}
/>
{/* */}
</div>
{checkContainerVisible && (
<div className="check-container">
Expand Down Expand Up @@ -373,7 +405,6 @@ function AskQuestionPage() {
</div>
</main>
</div>
<Footer />
{/* footer 넣을자리 */}
</StyleAskPage>
);
Expand Down
47 changes: 47 additions & 0 deletions client/src/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// store.js

import { createStore } from 'redux';

// 초기 상태 설정
const initialState = {
checkContainerVisible: false,
isChecked: false,
titleButtonVisible: true,
tagButtonVisible: false,
reviewButtonVisible: false,
editorButtonVisible: false,
editor2ButtonVisible: false,
isDropdownOpen: false,
editorContent: '',
};

// 리듀서 함수, 액션에 따라 상태를 업데이트
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case 'SET_CHECK_CONTAINER_VISIBLE':
return { ...state, checkContainerVisible: action.payload };
case 'SET_IS_CHECKED':
return { ...state, isChecked: action.payload };
case 'SET_TITLE_BUTTON_VISIBLE':
return { ...state, titleButtonVisible: action.payload };
case 'SET_TAG_BUTTON_VISIBLE':
return { ...state, tagButtonVisible: action.payload };
case 'SET_REVIEW_BUTTON_VISIBLE':
return { ...state, reviewButtonVisible: action.payload };
case 'SET_EDITOR_BUTTON_VISIBLE':
return { ...state, editorButtonVisible: action.payload };
case 'SET_EDITOR2_BUTTON_VISIBLE':
return { ...state, editor2ButtonVisible: action.payload };
case 'SET_IS_DROPDOWN_OPEN':
return { ...state, isDropdownOpen: !state.isDropdownOpen };
case 'SET_EDITOR_CONTENT':
return { ...state, editorContent: action.payload };
default:
return state;
}
};

// 스토어 생성
const store = createStore(rootReducer);

export default store;

0 comments on commit 9e02410

Please sign in to comment.