React를 이용하여 간단한 익명게시판을 만들었다. 이제 몇가지 기능을 추가하여서 더욱 익명게시판다운 모습을 만들어 보이도록 하자. 익명게시판에서 지원하는 기능은 다음과 같다.
우리가 지난 시간에는 모든 Component 요소를 무식하게 App.jsx
에 모두모두 몰아 넣었다. 이제 Header
, PostList
, Footer
, Slogun
부분으로 나누어서 Component를 분리해보자. 사실은 노가다 작업인데, StyleComponent 몇가지 이름이 겹치는 게 있어서 그것 좀 바꿔주느라고 노가다를 했다.
Header.jsx
import {
HeaderDiv,
TitleLogoDiv,
TitleBig,
TitleSmall,
SubHeaderDiv,
} from './styledComponent';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSun, faMoon } from '@fortawesome/free-solid-svg-icons';
function Header({darkMode, setDarkMode}) {
const toggleDarkMode = () => {
setDarkMode((darkMode)=> ! darkMode);
};
return (
<HeaderDiv>
<TitleLogoDiv>
<TitleBig>고민</TitleBig>
<TitleSmall>익명게시판</TitleSmall>
</TitleLogoDiv>
<SubHeaderDiv>
{darkMode ? (
<div>
<FontAwesomeIcon onClick = {toggleDarkMode} icon = {faSun}/>
</div>
) : (
<div>
<FontAwesomeIcon onClick = {toggleDarkMode} icon = {faMoon}/>
</div>
)}
</SubHeaderDiv>
</HeaderDiv>
);
}
export default Header
ShowPostList.jsx
import {
EachPostLi,
LoadingDiv,
LoadingImg,
PagenumberDiv,
PagingSection,
PostLink,
PostListDiv,
PostRepl,
PostSection,
PostTitle,
PostTitleDiv,
} from './styledComponent';
import {
faSun,
faMoon,
faArrowsRotate,
faPenToSquare,
faLocationPin,
faArrowLeft,
faArrowRight,
faSlidersH,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
function ShowPostList({isPost, loading}){
return (
<>
<PostSection>
<PostTitleDiv>
<FontAwesomeIcon icon = {faArrowsRotate} />
<PostTitle>익명게시판</PostTitle>
<FontAwesomeIcon icon = {faPenToSquare} />
</PostTitleDiv>
<PostListDiv>
{loading ? (
<LoadingDiv>
<LoadingImg src = {'./loading.svg'}/>
</LoadingDiv>
) : isPost ? (
<LoadingDiv>
아직 기록된 글이 없습니다.
</LoadingDiv>
) : (
<ul>
<EachPostLi>
<div>
<FontAwesomeIcon
icon ={faLocationPin}
/>
<PostLink>
React가 너무 재미있어요.
</PostLink>
</div>
<PostRepl>[35]</PostRepl>
</EachPostLi>
</ul>
)}
</PostListDiv>
</PostSection>
<PagingSection>
<PagenumberDiv>
<FontAwesomeIcon icon = {faArrowLeft}/>
</PagenumberDiv>
<PagenumberDiv>2</PagenumberDiv>
<PagenumberDiv>
<FontAwesomeIcon icon ={faArrowRight}/>
</PagenumberDiv>
</PagingSection>
</>
)
}
export default ShowPostList
Slogun.jsx
import {
SlogunBig,
SlogunSection,
SlogunSmall,
} from './styledComponent';
function Slogun(){
return (
<SlogunSection>
<SlogunBig>자유롭게 의견을 나누어요</SlogunBig>
<SlogunSmall>악플은 금물!</SlogunSmall>
</SlogunSection>
)
}
export default Slogun
Footer.jsx
import {
FooterDiv,
FooterSmall,
FooterBig,
} from './styledComponent';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faReact } from '@fortawesome/free-brands-svg-icons';
function Footer(){
return (
<FooterDiv>
<FontAwesomeIcon icon = {faReact} />
<FooterBig>for react study</FooterBig>
<FooterSmall>2022.by Eugene</FooterSmall>
</FooterDiv>
)
}
export default Footer
App.jsx
import {
Main,
MediaDiv,
} from './styledComponent';
import Header from './Header';
import Slogun from './Slogun';
import { darkTheme, GlobalStyles, lightTheme } from './styles';
import { ThemeProvider } from 'styled-components';
import {useState} from 'react';
import ShowPostList from './ShowPostList';
import Footer from './Footer';
function App() {
const [darkMode, setDarkMode] = useState(true);
const loading = false;
const isPost = false;
return (
<>
<ThemeProvider theme ={darkMode ? darkTheme : lightTheme}>
<GlobalStyles/>
<MediaDiv>
<Header darkMode = {darkMode} setDarkMode = {setDarkMode}/>
<Main>
<Slogun />
<ShowPostList/>
</Main>
<Footer />
</MediaDiv>
</ThemeProvider>
</>
)
}
export default App;
모든 컴포넌트 분리 완료!! 이제 props & state를 이용하여 구현하고자 하는 기능을 구현해보자.
먼저 배열 형식으로 게시글의 제목과 댓글을 정리해야한다. 이를 먼저 구현해봅시다. EachPostLi
라는 새로운 컴포넌트를 만들어둡시다. 그리고 아래 코드와 같이 작성해볼까요~이 컴포넌트는 각각의 게시글을 나타내는데 쓰이는 요소입니다^^
EachPostLi.jsx
import {
EachPostLi,
PostLink,
PostRepl,
} from './styledComponent';
import {
faLocationPin,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
function EachPost({title,replCount}) {
return (
<EachPostLi>
<div>
<FontAwesomeIcon icon ={faLocationPin} />
<PostLink>
{title}
</PostLink>
</div>
<PostRepl>{replCount}</PostRepl>
</EachPostLi>
);
}
export default EachPost;
기존에 있던 내용을 지우고, props 값을 받아와 사용하기 위하여 인자로 {title,replCount}
를 넘겨받습니다. 그리고 그 값을 사용하기 위하여 {title}
과 {replCount}
값을 넣어요.
그럼 내가 생성하는 값에 따라서 자동으로 여기다가 값을 넣어주는 것입니다.
이제 App,jsx
파일을 수정해보자.
import {
Main,
MediaDiv,
} from './styledComponent';
import Header from './Header';
import Slogun from './Slogun';
import ShowPostList from './ShowPostList';
import Footer from './Footer';
import { darkTheme, GlobalStyles, lightTheme } from './styles';
import { ThemeProvider } from 'styled-components';
import {useState} from 'react';;
function App() {
const initialPostList = [
{id : 1, title : '리액트 공부는 재미있어.', replCount : 1},
{id : 2, title : '프론트 공부 열심히 해.', replCount : 43},
{id : 3, title : '파이팅^^.', replCount : 1},
];
const [darkMode, setDarkMode] = useState(true);
const [loading, setLoading] = useState(false);
const [isPost, setIsPost] = useState(false)
const [postList, setPostList] = useState(initialPostList);
const addPost = () => {
setPostList((postList) => [
...postList, {id : 4, title :'공부는 열심히 하면 좋아.', replCount : 21},
]);
};
return (
<>
<ThemeProvider theme ={darkMode ? darkTheme : lightTheme}>
<GlobalStyles/>
<MediaDiv>
<Header darkMode = {darkMode} setDarkMode = {setDarkMode}/>
<Main>
<Slogun />
<ShowPostList loading = {loading} isPost = {isPost} postList = {postList} addPost = {addPost}/>
</Main>
<Footer />
</MediaDiv>
</ThemeProvider>
</>
)
}
export default App;
값을 변경할 수 있도록 useState
를 사용하여 직접 인수값을 넘겨받는 형태로 바꾸었다.
이 변수들을 생성해 주었으니 각각의 Component에 값을 내려주어야 한다. 그래서 다음과 같은 코드들을 작성한 것!
<Header darkMode = {darkMode} setDarkMode = {setDarkMode}/>
<ShowPostList loading = {loading} isPost = {isPost} postList = {postList} addPost = {addPost}/>
여기서 addPost
함수의 기능은, 새로고침 버튼을 눌렀을 때, 게시글 목록에 새로운 게시글을 추가해주는 것이다. postList
에 새로운 리스트를 추가하는 것이 함수의 기능이다.
그리고 initialPostList
는 작성된 게시글을 리스트로 보여주는 형식을 가지고 있다. 각각의 id, post, 댓글수를 요소로 가지고 있고 배열의 형태로 저장되어 화면에 출력되는 것이다.
다만 여기서 주의해야 할 점은 useState
를 사용하기 위하여 이것을 꼭 import 해주어야 한다.
각각의 Post를 보여주는 EachPost.jsx
를 생성하였으니 기존에 포스트를 보여주던 jsx 파일을 수정하여 보자. 바로 ShowPostList.jsx
이다!
...
import EachPost from './EachPost';
function ShowPostList({ isPost, loading, addPost, postList }){
return (
<>
<PostSection>
<PostTitleDiv>
<FontAwesomeIcon onClick = {addPost} icon = {faArrowsRotate} />
<PostTitle>익명게시판</PostTitle>
<FontAwesomeIcon icon = {faPenToSquare} />
</PostTitleDiv>
<PostListDiv>
{loading ? (
<LoadingDiv>
<LoadingImg src = {'./loading.svg'}/>
</LoadingDiv>
) : isPost ? (
<LoadingDiv>
아직 기록된 글이 없습니다.
</LoadingDiv>
) : (
<ul>
{postList.map((element) => (
<EachPost
key={element.id}
title = {element.title}
replCount = {element.replCount}
/>
))}
</ul>
)}
</PostListDiv>
...
역시나 ShowPostList는 네 개의 변수인 isPost
, loading
, addPost
,postList
를 받습니다. 그리고 이를 이용하여 자신들의 할 일을 수행하지요. onClick
을 통하여, addPost
라는 이벤트를 발생시키고, 상단의 아이콘을 클릭하면 새로운 글이 자꾸 추가되는 것을 관찰할 수 있다. 그리고 map
을 이용하여, 배열을 순서대로 잘 나타내고 있다. 이럴 때 map
이라는 함수를 사용한다는 점을 잊지 말자!
이렇게 하면 새로고침을 할 때마다 새로운 게시글이 올라오게 된다.
다크모드 아이콘 활성화도 똑같이 useState
를 이용하고, onclick
을 사용하면 된다.
App,jsx
코드를 수정하여 보자.
function App() {
...
const [darkMode, setDarkMode] = useState(true);
...
return (
<>
<ThemeProvider theme ={darkMode ? darkTheme : lightTheme}>
<GlobalStyles/>
<MediaDiv>
<Header darkMode = {darkMode} setDarkMode = {setDarkMode}/>
<Main>
<Slogun />
<ShowPostList loading = {loading} isPost = {isPost} postList = {postList} addPost = {addPost}/>
</Main>
<Footer />
</MediaDiv>
</ThemeProvider>
</>
)
}
export default App;
그리고 Header.jsx
로 이동하여 다음 코드를 수정해보자.
...
function Header({darkMode, setDarkMode}) {
const toggleDarkMode = () => {
setDarkMode((darkMode)=> ! darkMode);
};
return (
<HeaderDiv>
<TitleLogoDiv>
<TitleBig>고민</TitleBig>
<TitleSmall>익명게시판</TitleSmall>
</TitleLogoDiv>
<SubHeaderDiv>
{darkMode ? (
<div>
<FontAwesomeIcon onClick = {toggleDarkMode} icon = {faSun}/>
</div>
) : (
<div>
<FontAwesomeIcon onClick = {toggleDarkMode} icon = {faMoon}/>
</div>
)}
</SubHeaderDiv>
</HeaderDiv>
);
}
export default Header
onClick
을 통하여, toggleDarkMode
라는 함수를 실행시켜주었다.
이렇게 해서 완성된 두번째 익명게시판이다.