본격적으로 기억과 감정이 아닌 하드스킬에 관한 부분을 기록하기 위해 WIL의 틀을 바꾸어봅니다.
백엔드(Java, Spring)과 프론트엔드(Javascript, React)간의 언어가 달라 소통에 어려움이 있었다. 클라이언트의 경우, res.json
으로 보내주세요 라고 이야기를 한다면 스프링 선생님들은 이를 이해하지 못한다. 원활한 소통을 위하여 그들의 언어를 미약하게나마 공부해야겠다는 생각이 들었다.
API 설계와 와이어 프레임은 반드시 탄탄하게 잡아야 한다. API 설계는 백엔드 개발자와 프론트엔드 개발자와의 약속이며 와이어 프레임은 프론트엔드 개발자와의 약속이다. 실제 개발은 이 약속대로 진행하면 된다. 중간에 변수가 생겨 바뀔지언정, 그 틀 안에서 바뀌는 것이기 때문에 유지 보수에도 용이하다. 그런데 이 과정이 탄탄하지 않는다면? 시간은 없는데 뭐를 받아서 UI를 그려주는지 모른다면? 정말로 힘들 것이다. 따라서 그 틀을 주관적이지만 비즈니스 로직과 일치하게 만들어 놓은다면, 모두가 하나의 추상적인 공간을 공유하고 있게 되므로, 코드를 더 빨리 작성할 수 있을 것이다.
나는 프론트 엔드 개발자에게 필요한 소양이 UI를 이쁘게 그리는 것에 국한된 것이라고 생각하지 않는다. 사용자가 편할 정도의 UI와, 그것보다 더 나은 UX를 제공하기 위해 로직을 구현하는 것이 진정 프론트엔드 개발자가 가져야할 소양이라고 생각한다. 최근 연이은 CSS 압박으로 많은 스트레스를 받았다. 내가 가지고 있는 장점은 UI적인 세심함보다는 UX와 로직에 대한 세심함이라고 생각하는데, 자꾸 그 장점이 단점으로 여겨져 자존감도 많이 떨어져 있다. 그렇다고 하던 것을 멈추고 CSS만 공부한다면 그것도 말이 안되지 않겠는가.. 하루에 조금이라도 UI 컴포넌트를 이쁘게 그리는 연습을 해보아야겠다. 어차피 둘 다 필요하다면 조금씩 하는게 안하는 것 보다 나으니깐 말이다.
더 많은 예외처리에 신경을 써야겠다. 스프링 선생님들께서 예외 처리를 어떤 형태로 하시는지 알지 못하여 이에 관한 토의를 해본 적이 없지만, Node는 예외에 대하여 throw로 던지므로 catch로 받아 원하는 렌더링 로직을 더 짤 수 있을 것이다. 다음 주에는 이런 예외처리를 목표로 구현해보아야겠다.
// 토큰을 헤더에 저장하는 axios 로직
import axios from 'axios';
import { getToken } from '../utils/auth';
const baseURL = process.env.REACT_APP_REMOTE_SERVER_URI;
const instance = axios.create({ baseURL });
const setToken = (config) => {
config.headers['Content-Type'] = 'application/json; charset=utf-8';
config.headers['X-AUTH-TOKEN'] = `${getToken()}`;
config.headers.withCredentials = true;
return config;
};
instance.interceptors.request.use(setToken);
export default {
GET: (endpoint, additionalPath) =>
instance.get(`${endpoint}${additionalPath ? `/${additionalPath}` : ''}`),
POST: (endpoint, body) => instance.post(endpoint, body),
UPDATE: (endpoint, urlParam, body) =>
instance.post(`${endpoint}/${urlParam}`, body),
DELETE: (endpoint, urlParam) => instance.delete(`${endpoint}/${urlParam}`),
};
// 유저의 로그인 유무 관련 로직
import React from 'react';
import { Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';
import Loading from './Loading';
import { useUserAuthentication } from '../hooks';
const Permit = ({ children }) => {
const [isUserAuthorized, token] = useUserAuthentication();
if (token && !isUserAuthorized) {
return <Loading />;
}
if (!(token || isUserAuthorized)) {
return <Redirect to="/sign" />;
}
return children;
};
Permit.propTypes = {
children: PropTypes.element.isRequired,
};
export default Permit;
import React from 'react';
import { validateEmail, matchPasswordLength } from '../utils';
export default function useValidation(type, initialValue) {
const [state, setState] = React.useState(
typeof initialValue === 'function' ? initialValue() : initialValue,
);
const [isStateValid, setIsStateValid] = React.useState(true);
const onChange = React.useCallback((nextState) => {
const value =
typeof nextState === 'function' ? nextState(state) : nextState;
setState(value);
if (value.length === 0) {
setIsStateValid(true); // input값이 아무것도 없다면 초기화한다.
return;
}
if (type === 'email') {
setIsStateValid(validateEmail(value));
return;
}
if (type === 'password') {
setIsStateValid(matchPasswordLength(value));
}
}, []);
return [state, isStateValid, onChange];
}
// useLocation 사용
React.useEffect(() => {
if (!location.search) {
return null;
}
const query = location.search;
const code = query.split('=')[1];
async function handleKaKaoLoginRedirection() {
try {
const { data } = await axios({
method: 'GET',
// 카카오는 쿼리스트링으로 보내야한다.
// 서버에서 처리하는 endpoint를 반드시 잡아놔야할 것
url: `${baseURL}/kakao/callback?code=${code}`,
});
saveToken(data.token);
dispatch(loginAction({ email: data.email, nickname: data.nickname }));
history.replace('/');
} catch (error) {
console.error(error);
}
}
handleKaKaoLoginRedirection();
}, []);