작성한사람만 자기 목록만 보이도록
post 요청을 할떄,
company, position, startDate, endDate
밖에 안줬다. 로그인한 사람의 id도 담아줘야함.
🔎 id는 어떻게 가져올수있을까?
토큰 - 이메일주소가 필요하니까 header 에다가 담아서. accessToken에 담아 넘겨준다.
careerViewTable.js
const CareerViewTable = () => {
//토큰이 저장되어있는 전역 상태변수 가져오기
const { accessToken, setAccessToken } = useContext(UserContext);
const onAddCareer = async () => {
// 정상적으로 실행되는 코드
try {
let res = await axios.post('/api/career',
{
company, position, startDate, endDate
},
{
headers: {
Authorization: `Bearer ${localStorage.getItem('accessToken')}`
}
}
);
//res.data에는 방금 추가한 객체가 들어있음
//성공했을때 뭔가 할것
alert('추가 완료!');
// window.location.reload(); //새로고침
//새로고침 대신 생각해 볼수있는것
//방금 추가한 객체를 이미 20개의 객체가 요소로 들어있는
//배열의 머지막 요소로 추가
setCareerList([...careerList, res.data]);
console.log([...careerList, res.data]);
} catch (err) {
console.log(err);
}
}
return(
<button onClick={onAddCareer}>추가</button>
);
}
app.js
//career 추가
app.post('/api/career', async (req, res) => {
// email은 header에 있는 token 에 들어있음
const token = req.headers.authorization.replace('Bearer ', '');
let { email } = jwt.verify(token, process.env.JWT_SECRET) //이메일만 뽑아서 쓰겠다.
const { company, position, startDate, endDate } = req.body;
let sql = `
insert into tbl_careers
(email, company, position, start_date, end_date)
values
(
?,
?,
?,
str_to_date(?, '%Y-%m-%d'),
${endDate === '' ? null : `str_to_date(?, '%Y-%m-%d')`}
);
`;
let values = [email, company, position, startDate];
if (endDate !== '') {
values.push(endDate);
}
try {
let [results] = await pool.query(sql, values);
console.log(results);
let [rows] = await pool.query('select * from tbl_careers WHERE id=?', [results.insertId])
console.log(rows);
res.json('커리어 추가 완료!');
} catch (err) {
console.log(err);
res.status(500).json('서버에서 오류 발생함');
}
});
🔎 최초 렌더링 될떄, 여기서 이메일정보도 같이 넘겨주면 되겠지❗️(header에다가)
careerViewTable.js
const CareerViewTable = () => {
const [careerList, setCareerList] = useState([]);
useEffect(() => {
//CareerViewTable이 최초 렌더링 될때 express 한테 careerList를 요청해서 받아온다.
const fetchCareerList = async () => {
try {
let res = await axios.get('/api/career',
{ headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` } }); //토큰을 보내줘야한다.
setCareerList(res.data);
} catch (err) {
console.log(err);
}
}
fetchCareerList();
}, []);
토큰이
req안
에 들어가있다. sql,where email = ?
를 설정해주고,
token을 받아온다.req 안에있는 headers에 authorization
그리고, 그 token안에서email만
쓰겠다.
pool.query(sql, [email])
👉 sql 실행할건데, 로그인한사람의 email을 넣어서 보여주세요.
app.js
app.get('/api/career', async (req, res) => {
try {
let sql = `
select id,
email,
company,
position,
date_format(start_date, '%Y년 %m월 %d일') start_date,
date_format(end_date, '%Y년 %m월 %d일') end_date
from tbl_careers
where email = ?
`
let token = req.headers.authorization.replace('Bearer ', ''); //token을 받아온다. req 안에있는 headers에 authorization.
let { email } = jwt.verify(token, process.env.JWT_SECRET); // 그 token안에서 email만 쓰겠다.
// mysql가서 커리어 리스트 받아오고 , email이 일치하는 커리어만 받아오기
let [results, fields] = await pool.query(sql, [email]);//sql 실행할건데, 로그인한사람의 email을 넣어서 보여주세요.
// 리액트한테 받아온 배열 응답하기
res.json(results);
} catch (err) {
console.log(err);
res.status(500).json('서버쪽 오류 발생');
}
});
🔎 처음에 로그인 성공하면,
App.js
그려지고 그안에login.js
App.js
속에 accessToken state변수를 만들고 ,
- 근데 여기서 새로고침을 하면,
App.js
부터 다시 그려진다.
그안에있는accessToken도 그래서 다시
그려지니까, 초기화가된다.state변수
초기값을 null 설정해놨기때문에, 초기화 되면null값
이 들어간다.
accessToken
사용하는 컴포넌트가 있다면, 확인해줘야함
상황 1) 로그인을 안해서 null -> localStorage에도 없음 상황 2) 로그인을 했는데 새로고침 했음 -> localStorage에는 있는데 accessToken에는 없음 => useEffect( ) 를 써야한다
그런데❗️
여기서, 로그인을해야 볼수있는 컴포넌트(DashboardHeader
,CareerViewTable
)를 갈때마다 그럼useeffect
로 매번 get 요청해서accessToken에 email
을 확인해야하는가 ❓
(header
에서도 필요하고,경력페이지
,활동게시판
,할일목록
다 필요한데...)너무 불편하잖아그럼..
그렇기 때문에 우리에겐 custom hook 함수가 있지 (hook함수를 직접 만들 수 있다)😁
📝
useEffect
의존성배열 속이 비어있으면 , 최초 한번만 실행된다.
accessToken이 존재하는지 안하는지 확인.
hooks.js
import {useContext, useEffect } from "react";
import {UserContext} from "../App";
import { useNavigate } from "react-router-dom";
// accessToken이 있는지 없는지 검사하는 hook함수
export const useAuth = ()=>{ //다른데서 사용가능하게 export해줌
//전역 state변수 가져오기(App.js에서)
const {accessToken, setAccessToken} = useContext(UserContext);
const navigate = useNavigate();
useEffect(()=>{
//1. 로그인이 안된 상태 localStorage의 accessToken null,
// 전역 상태변수 accessToken null
if(localStorage.getItem('accessToken') === null){
alert('로그인이 필요한 페이지 입니다!');
navigate('/login', {replace : true});
return;
}
// 2. 로그인은 되었으나 새로고침한 상태 accessToken 있음,
// 전역 상태변수 accessToken null
if(accessToken === null){
setAccessToken(localStorage.getItem('accessToken'));
return;
}
// 3. 로그인 되었고, 새로고침도 안함
// localStorage에 accessToken 있음,
// 전역 상태변수 accessToken 있음
}, [accessToken, setAccessToken, navigate]); //accessToken, setAccessToken, navigate 바뀌면 실행시켜줘
}
📝이제
useAuth()
custom hook만든걸로 필요한곳에 사용해보자.
header.js
import { useAuth } from "../hooks/hooks";
const DashboardHeader = () => {
useAuth(); //만든 hook함수를 여기다 쓴다고 써줘
// 전역state변수에 있는 토큰 값 가져오기
const {accessToken, setAccessToken} = useContext(UserContext);
useEffect(() => {
let tmp = async () => {
if(accessToken === null) return; //accessToken이 null이면 아래 코드 실행 안함 바로 종료
try {
let res = await axios.get('/api/loggedInEmail',
{ headers: { Authorization: `Bearer ${accessToken}` } } // 전역상태변수 accessToken 가져와서 사용가능.
);
}
tmp();
// axios.get('/api/users/로그인한사람id');
}, [accessToken]); //accessToken 바뀌면, 다시 실행
}
그럼 이제 accessToken 전역변수 객체를 바로 가져와서 사용해도된다.
{ headers : {Authorization : `Bearer ${localStorage.getItem('accessToken')}`}}
=> {headers : {Authorization:`Bearer ${accessToken}`}} // 전역상태변수 accessToken 가져와서 사용가능.
근데, 또 문제점이 있지❗️ useAuth 낭비..
로그인이 안되어있으면, 전체가 안보이게
전체에다가 쓰면되지 않을까?
하나씩 하나씩 불러서 사용하는것보단?
이렇게 하나로 만들면 되지않을까?
career.js
import DashboardLayout from "../../components/common/layout";
import { Title } from "../../styles/dashboard/career.styles";
import CareerViewTable from "../../components/career/careerViewTable";
import { useAuth } from "../../components/hooks/hooks";
const CareerPage = () => {
useAuth();
return (
<DashboardLayout>
<Title>나의 경력을 관리하세요</Title>
<p>회사, 직위, 일자를 입력한 후 경력을 추가해 보세요!</p>
<CareerViewTable />
</DashboardLayout>
)
}
export default CareerPage;
career page 안에, CareerViewTable로 넘어오기때문에, 여기도 전역변수 accessToken로 바꿔준다.
CareerViewTable .js
import { useContext } from "react";
import { UserContext } from "../../App";
const CareerViewTable = () => {
const { accessToken, setAccessToken } = useContext(UserContext);
useEffect(() => {
//CareerViewTable이 최초 렌더링 될때 express 한테 careerList를 요청해서 받아온다.
const fetchCareerList = async () => {
if (accessToken === null) return; //accessToken이 null이면 아래 코드 실행 안함 바로 종료
try {
let res = await axios.get('/api/career',
{ headers: { Authorization: `Bearer ${accessToken}` } }); //토큰을 보내줘야한다.
setCareerList(res.data);
} catch (err) {
console.log(err);
}
}
fetchCareerList();
}, [accessToken]);
예를들어, 간단하게 설명하자면, (보통은 더 길게 함수가 쓰이면 사용하면 좋지만, 이것은 예를 들을려고 하는것)
다른데서도 사용가능하게
코드가 많아지면 복잡할수있으니까, 보기좋게custom hooks
를 만들어서 사용할수있다.
- use로 시작하면 hook함수다.
hooks.js
// 페이지 이동을 위한 hook 함수
export const useMove = (dir)=>{ //다른데서 사용할수있게 export쓰는거 잊지말고.
const navigate = useNavigate();
return ()=>{navigate(dir)}
}
// 페이지 이동인데 뒤로가기 못하게 이동하는 hook함수
export const useReplace = (dir)=>{
const navigate = useNavigate();
navigate(dir, {replace : true});
}
index.js
import { useNavigate } from "react-router-dom";
const IndexPage = () => {
let navigate = useNavigate();
return (
<>
<h1>main page</h1>
<button onClick={()=>{
navigate('/login');
}}>login</button>
<button>회원가입하기</button>
<button>커리어</button>
</>
)
}
export default IndexPage;
index.js
import { useMove } from "../hooks/hooks";
const IndexPage = ()=>{
let moveToLoginPage = useMove('/login');
let moveToJoinPage = useMove('/join');
let moveToCareerPage = useMove('/career');
return(
<>
<h1>메인페이지 입니다</h1>
<button onClick={moveToLoginPage}>로그인하기</button>
<button onClick={moveToJoinPage}>회원가입하기</button>
<button onClick={moveToCareerPage}>커리어</button>
</>
)
}
export default IndexPage;
일반 함수에서 사용 🚫
콜백 함수에서 사용 🚫
- 그럼 어디서 사용하면 될까?
- useEffect 나 다른 use훅함수가 그려질때 사용