accessToken 이 null값이면 바로 종료;
useEffect(() => {
let tmp = async () => {
try {
if(accessToken === null){
return; //accessToken 이 null값이면 바로 종료;
}
let res = await axios.get(
`/api/activities?order=${order}&limit=${cntPerPage}&page=${currentPage}&q=${searchText}`,
{headers : {Authorization : `Bearer ${accessToken}`}}
);
}
tmp();
}, [currentPage, order, searchText, accessToken]);
select *
from (select a.id,
a.title,
a.content,
a.writer_email,
a.created_date,
a.updated_date,
a.activity_view,
IFNULL(b.like, 0) "activity_like"
from tbl_activities a left outer join (
select activity_id, count(*) "like"
from tbl_activity_like
group by activity_id
) b
on a.id = b.activity_id) c left outer join (select * from tbl_activity_like
where email = '1234@test.com') d
on c.id = d.activity_id;
app.js
app.get('/api/activities', async (req, res) => {
// sql
let sql = `
select c.id ,
c.title,
c.content,
c.writer_email,
c.created_date,
c.updated_date,
c.activity_view,
c.activity_like,
if(d.email is null, 'no', 'yes') "liked"
from (select a.id,
a.title,
a.content,
a.writer_email,
a.created_date,
a.updated_date,
a.activity_view,
IFNULL(b.like, 0) "activity_like"
from tbl_activities a left outer join (
select activity_id, count(*) "like"
from tbl_activity_like
group by activity_id
) b
on a.id = b.activity_id) c left outer join (select * from tbl_activity_like
where email = ?) d
on c.id = d.activity_id
where title like ?
`;
try {
// 로그인 한 사람의 이메일 정보
const token = req.headers.authorization.replace('Bearer ', '');
// console.log(token);
const user = jwt.verify(token, process.env.JWT_SECRET);
let [results] = await pool.query(sql, [user.email, `%${q}%`, limit, limit * (page - 1)]);
// console.log(results);
//각 게시물에 대한 이미지 가져오기
sql = `
select img_url
from tbl_activity_img
where activity_id = ?
`
//각각의 게시물 이미지 url을 각 객체속에 추가
for (let i = 0; i < results.length; i++) {
let [imgs] = await pool.query(sql, [results[i].id])
console.log(imgs);
results[i].img_url = imgs.map((el) => el.img_url);
}
console.log(results); //img_url 추가된 results
// 전체게시물 갯수
sql = `
select count(*) "total_cnt"
from tbl_activities
where title like ?
`
const [results2] = await pool.query(sql, [`%${q}%`]);
console.log(results2); // [ {total_cnt: 5} ]
res.json({ total_cnt: results2[0].total_cnt, activityList: results });
} catch (err) {
console.log(err);
res.status(500).json('오류발생했음');
}
});
하트가 이미 눌렸으면, 새로고침해도 하트가 눌린채 가져온다.
const [isLiked, setIsLiked] = useState(props.activity.liked === 'yes'); //좋아요 여부
activityCard.js
import { UserContext } from "../../App";
import { useContext, useState } from "react";
import axios from "axios";
const ActivityCard = (props) => {
console.log(props.activity);
const [isLiked, setIsLiked] = useState(props.activity.liked === 'yes'); //좋아요 여부
const { accessToken } = useContext(UserContext);
const onLikeClick = async () => {
if (accessToken === null) {
alert('로그인 후 이용해주세요');
navigate('/login');
return;
}
if (isLiked === false) {//🌟하트가 안눌린 상태에서 하트를 누르면
//지금 로그인 한 사람이, 해당 게시물에 하트를 누른것 --> 데이터 베이스 테이블에 추가
try{
await axios.post('/api/like',
{id:props.activity.id} ,
{headers:{Authorization:`Bearer ${accessToken}`}}
);
setIsLiked(true);
}catch(err){
console.log(err);
alert('현재 서버에 문제가 있어요 잠시후 다시 시도하세요');
}
}else{ //🌟하트가 눌린 상태에서 하트를 해제한것
//지금 로그인한 사람이 해당 게시물 하트 해제한것 -->테이블 삭제
try{
await axios.delete('/api/like', {
data : {id:props.activity.id},
headers:{Authorization:`Bearer ${accessToken}`}
});
// setIsLiked(false);
}catch(err){
console.log(err);
alert('잠시후 다시 실행하세요');
}
}
}
return (
<CardLikeButton onClick={onLikeClick}>
{isLiked ? <FavoriteIcon style={{ color: 'red' }} /> : <FavoriteBorderIcon />}
</CardLikeButton>
//like버튼이 클릭되면,
);
//🌟좋아요 테이블에 추가 - 필요한 정보 ( 리액트가 줘야하는건 게시물 id, 로그인한사람의 email)
app.post('/api/like', async (req, res) => {
const id = req.body.id //body 안에 id가 들어있음/ 게시물 id
const token = req.headers.authorization.replace('Bearer ', '');
const user = jwt.verify(token, process.env.JWT_SECRET);
//user.email --> 로그인한 사람의 email
let sql = `
insert into tbl_activity_like
values (?, ?);
`
try {
await pool.query(sql, [id, user.email]);
res.json('추가 성공!');
} catch (err) {
console.log(err);
res.status(500).json('오류발생했음');
}
})
//🌟좋아요 테이블에서 삭제 ( 리액트가 줘야하는건 게시물 id, 로그인한사람의 email)
app.delete('/api/like', async (req, res) => {
const id = req.body.id //body 안에 id가 들어있음/ 게시물 id
const token = req.headers.authorization.replace('Bearer ', '');
const user = jwt.verify(token, process.env.JWT_SECRET);
//user.email --> 로그인한 사람의 email
let sql = `
delete from tbl_activity_like
where activity_id = ? and email = ?;
`;
try {
await pool.query(sql, [id, user.email]);
res.json('삭제 성공!');
} catch (err) {
console.log(err);
res.status(500).json('오류발생했음');
}
})
activityDetail.js
import { useParams } from "react-router-dom";
import DashboardLayout from "../../components/common/layout";
import { useAuth } from "../../components/hooks/hooks";
import ActivityDetailSection from "../../components/activity/activityDetailSection";
const ActivityDetailPage = ()=>{
useAuth(); //로그인한후 사용가능
const params = useParams();
// console.log(params);
return(
<DashboardLayout target="활동게시판">
<h1>{params.id}번 게시글 상세 페이지</h1>
<ActivityDetailSection activityId={params.id}/>
</DashboardLayout>
);
}
export default ActivityDetailPage;
📌 먼저 UI를 만든다.
activityDetailSection.js
import { BoardContent, BoardDetailWrap, BoardInfoWrap, BoardTitle, WriteBtn } from "../../pages/dashboard/activityDetail.styles";
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
import FavoriteIcon from '@mui/icons-material/Favorite';
const ActivityDetailSection = (props) => {
return (
<section>
<BoardDetailWrap>
<BoardTitle>
제주도 여행 후기
<div>
<span>좋아요:57</span>
<span onClick={onLikeClick}>
{isLiked ? <FavoriteIcon style={{ color: 'red' }} /> : <FavoriteBorderIcon />}
&</span>
</div>
</BoardTitle>
<BoardInfoWrap>
<p>작성자</p>
<p>123@test.com</p>
<p>작성일</p>
<p>2021-09-09</p>
</BoardInfoWrap>
<BoardInfoWrap>
<p>작성일자</p>
<p>2021-09-20</p>
<p>수정일자</p>
<p>2021-09-09</p>
</BoardInfoWrap>
<BoardInfoWrap>
<p>좋아요</p>
<p>40</p>
</BoardInfoWrap>
<BoardContent>
게시물 내용
</BoardContent>
<div style={{
alignSelf: 'flex-end',
display: 'flex',
columnGap: '10px'
}}>
<WriteBtn>수정</WriteBtn>
<WriteBtn style={{ backgroundColor: 'red' }}>삭제</WriteBtn>
</div>
</BoardDetailWrap>
</section>
)
}
export default ActivityDetailSection;
activityDetail.styles.js
import styled from "@emotion/styled";
export const BoardDetailWrap = styled.div`
display: flex;
flex-direction: column;
margin: 0 auto;
`;
export const BoardTitle = styled.div`
border-top: 1px solid black;
border-bottom: 1px solid silver;
font-size: 18px;
padding: 20px;
background-color: #e9e9e9;
display: flex;
justify-content: space-between;
align-items: baseline;
& span{
font-size: 14px;
}
`;
export const BoardInfoWrap = styled.div`
display: flex;
border-bottom: 1px solid silver;
&>p{
padding: 20px;
}
& > p:nth-of-type(odd){
width: 20%;
text-align: center;
border-right: 0.5px solid silver;
border-left: 0.5px solid silver;
}
& > p:nth-of-type(even){
width: 40%;
}
`;
export const BoardContent = styled.div`
padding: 40px 20px;
border-bottom:1px solid silver;
`;
export const WriteBtn = styled.button`
align-self:flex-end;
margin-top: 20px;
border-radius: 0;
padding: 6px 20px;
border: none;
background-color: #e9e9e9;
cursor: pointer;
`;
🔎
activityDetail.js
에서activityId={params.id}
를props
로 전달받았다.
activityDetailSection.js
import { useState, useEffect, useContext } from "react";
import { BoardContent, BoardDetailWrap, BoardInfoWrap, BoardTitle, WriteBtn } from "../../styles/dashboard/activityDetail.styles";
import axios from "axios";
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
import FavoriteIcon from '@mui/icons-material/Favorite';
import { UserContext } from "../../App";
const ActivityDetailSection = (props) => { //props받고 (activityDetail에서)
// const params = useParams();
const [isLiked, setIsLiked] = useState(false); //좋아요 여부
const { accessToken } = useContext(UserContext);
useEffect(() => {
let tmp = async () => {
if(accessToken === null) return;
let res = await axios.get(`/api/activities/${props.activityId}`, //아이디에다르게 가져다줘 activityDetail에서 사용한 params.id를 props로 받아와서 사용.
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
console.log(res.data);
}
tmp();
}, [props.activityId, accessToken]);
app.js
app.get('/api/activities/:id', async (req, res) => {
const id = req.params.id; // 리액트가 준 게시물 id
// console.log(id);
const token = req.headers.authorization.replace('Bearer ', '');
const user = jwt.verify(token, process.env.JWT_SECRET);
let sql = `
select * from
tbl_activities
where id = ?
`; //조회수까지나옴
try {
let [ result1 ] = await pool.query(sql, [id]); // result = id에 조회수까지
res.json('ddd');
} catch {
res.status(500).json('오류발생했음');
}
});
속도는 이게 더 느림 (하는방식만 알면됨)
let sql = ` select * from tbl_activities where id = ? `;//아이디에서 조회수까지
👇
app.js
app.get('/api/activities/:id', async (req, res) => {
const id = req.params.id; // 리액트가 준 게시물 id
// console.log(id);
const token = req.headers.authorization.replace('Bearer ', '');
const user = jwt.verify(token, process.env.JWT_SECRET);
let sql = `
select * from
tbl_activities
where id = ?
`;//아이디에서 조회수까지
try {
let [ result1 ] = await pool.query(sql, [id]);
sql = `
select count(*) "activity_like"
from tbl_activity_like
where activity_id = ?;
`; //좋아요갯수
let [result2] = await pool.query(sql, [id]);
sql = `
select * from tbl_activity_like
where activity_id = ? and email = ?;
`; //하트를 누른지 안누른지 확인여부 & 로그인한 사람이 있다면, 결과가 있고, 아니면 없을것이다.
let [result3] = await pool.query(sql, [id, user.email]);
sql = `
select * from tbl_activity_img
where activity_id = ?
`; //이미지url
let [result4] = await pool.query(sql, [id]);
//🌟 다 하나하나 만들고 이제, 하나로 합친다.
result1[0].activity_like = result2[0].activity_like; //result2는 좋아요갯수를 가져옴. 가져온것을 result1안에 넣어준다.
result1[0].liked = result3.length === 0 ? 'no' : 'yes'; //좋아요눌렀는지 안눌렀는지 여부는 result3에.
result1[0].img_url = result4.map((el)=> el.img_url)//이미지 url
console.log(result1[0]);
res.json(result1[0]); // 모두다 result1[0] 에 넣어주고 리액트로 보낸다.
}catch(err){
res.status(500).json('오류발생');
}
});
console.log(result1[0]); //안에 다 들어감
to be continued..🌟