export async function action({request}) {
const searchParams = new URL(request.url).searchParams;
const mode = searchParams.get('mode') ||'login';
if(mode !== 'login' && mode !=='signup') {
throw json({message: 'Unsupported mode'}, {status: 422});
}
const data=await request.formData();
const authData = {
email: data.get('email'),
password: data.get('password'),
};
const response= await fetch('http://localhost:8080/' +mode,
{
method:'POST',
headers : {"Content-Type":"application/json",},
body: JSON.stringify(authData)
});
//오류처리
if (response.status === 422 || response.status === 401) {
return response;
}
if(!response.ok){
throw json({message:'응답오류'}, {status: 500});
}
-서버에서 돌아온 응답에서 토큰을 추출 후 로컬 스토리지에 저장하는 작업도
여기 액션함수에 포함된다. 로그인에 성공하면 redirect으로 페이지를 이동시켜준다.
//서버에서 돌아온 응답에서 토큰 추출 후 로컬스토리지에 저장
const resData= await response.json();
const token= resData.token;
localStorage.setItem('token', token);
//로그인에 성공하면=>
return redirect('/');
}
1-2. useActionData : 서버측에 유효성을 검사하는데 씌인다.
1-3. useNaviagation: navigation.state로 현재상태를 화면에 표시
2.유저만 사용하는 페이지에 토큰 포함
2-1. getAuthToken 이라는 함수를 따로 만들어서 사용하면 편리하다
export function getAuthToken(){
const token= localStorage.getItem('token');
return token;
}
//로그아웃 시 useRouteLoader와 함께 유용하게 사용할 수 있다.
export function tokenLoader(){
return getAuthToken();
}
2-2. 유저만 사용하는 컴포넌트의 action() 함수 내부에 추가
const token = getAuthToken()
headers : {'Authorization':'Bearer '+ token}
3. 로그아웃
3.1 로그아웃 컴포넌트를 추가 하고 app.js에서 loader에 담아서 관리 해주는 방식을 사용할 것이다. 장점: 리액트 라우트 돔이 자동으로 토큰이 있는지 없는지 확인을 하고 token을 다시 fetch 해준다.
//1)로그아웃 컴포넌트 추가
export function action () {
localStorage.removeItem ('token');
return redirect('/')
2)로그아웃 버튼을 Form 형태로 action을 통해 트리거하고 '/logout으로 라우트된다.
<Form action="/logout" method="post">
<button>log out</button>
</Form>
//App.js에 라우트 추가
{path: 'logout',
action: logoutAction }
//화면 역시 변경해줘야 유저가 볼수 있는 컴포넌트 , 아닌 것이 구분된다.
//아래와 같이 전체를 포괄하는 root 라우터에 써줘야 모두 적용된다.
path: "/",
element: <RootLayout />,
errorElement: <ErrorPage />,
//util 파일에서 추가해준 함수를 로더 안에 넣는다.
//로더에서 토큰이 있는지 없는지 재평가 해준다.
loader: tokenLoader,
id: 'root',
//불러올때는 const token = useRouteLoaderData("root"); 그리고
jsx 랜더링 부분에 추가해준다.
{!token && (
<li>
{" "}
<NavLink
to="/auth?mode=login"
className={({ isActive }) =>
isActive ? classes.active : undefined
}
>
Authentication
</NavLink>
</li>
)}