[Toy] YesOrNo

걸음걸음·2023년 2월 27일
0

Project

목록 보기
1/6
post-thumbnail

소개

제작 기한 : 2023. 02. 24 ~ 2023. 02. 27 (ver 1.0.0)
사이트 링크 / 깃허브 링크
질문에 랜덤으로 긍정/부정을 돌려주는 사이트 (재미로 해주세요)

사용 OpenAPI 주소
반환 값 예시
{"answer":"yes","forced":false,"image":"https://yesno.wtf/assets/yes/5-64c2804cc48057b94fd0b3eaf323d92c.gif"}

사용 스택

  • ReactJS
  • styled-components
  • axios
  • gh-pages
파일 구조
/src
├── /API          # API요청 함수가 들어있는 폴더 < AsyncThunk적용으로 삭제
├── /components   # 사용한 컴포넌트 폴더
├── /global       # 전역에서 사용하는 스타일, 컬러를 담은 폴더
├── /images
├── /UI           # 스타일 관련 파일을 담은 폴더
├ App.js
└ index.js

구현 기능

데이터에 따른 표시 변경


API를 통해 받아온 데이터를 메인 박스의 UI를 나타내는 파일에 전달, 해당 데이터의 'answer'값에 따라 표시되는 색상이 다르도록 구현.

# 관련 코드
const AppBg = styled.div`
  (생략)
  background-color: ${(props) =>
    props.data
      ? props.data.answer === 'no'
        ? `${RADICALRED}`
        : `${DARKTURQUOISE}`
      : `${WHITE}`};
`;

응답을 다양한 형태로 표현

API 요청을 했을 때 받아오는 Gif 파일은 여러가지인 반면 answer은 'yes'와 'no' 두가지 형태밖에 없어, Math.random 메서드를 사용하여 이를 다양하게 나타내고자 했다.

# 응답 종류
const yes = ['응!','좋아!','해!','YESSSS!!','OK!!','좋아요',...];
const no = ['안돼!','하지마!','Nooooo!!!!','Nope','하지마세요',...];

(생략)

# 표시 코드
<h2>
 A:{data.answer === 'no'
    ? no[Math.floor(Math.random() * no.length)]
    : yes[Math.floor(Math.random() * yes.length)]}
</h2>

키워드 제공


처음 input창에 focus를 맞췄을 때 전체 키워드를 보여주고, 입력 중 관련된 키워드를 계속해서 보여주는 기능 구현. 화살표로 키워드를 선택하고 입력할 수 있다.
관련 코드가 있는 컴포넌트

어려웠던 부분

input - button 위치

'묻기!' 버튼을 클릭하였을 때 입체적인 효과를 주고자 box-shadow:inset과 padding 효과를 부여. 버튼의 효과는 의도한 것처럼 나왔으나, 버튼을 눌렀을 때 옆의 input 위치가 함께 움직이는 오류가 발생했다. input의 위치를 확인해봐도 변동하는 부분은 없어서 이유를 찾던 중 input과 button을 포함하고 있는 form의 크기가 유동적이기 때문에 생긴 문제임을 확인
form에 display:flex 와 align-items: flex-start 속성 부여
form의 정렬 기준이 아랫줄이었기 때문에, button의 padding 속성에 따라 아랫줄에 변동이 일어나자 옆의 input이 함께 움직인 것. 그래서 align-items: flex-start 속성을 통해 정렬 기준을 윗줄로 변경시켰다.

제공 키워드의 표시 유무

제공 키워드를 표시하는 true/false 상태 제어를 input의 focus와 blur로 하려 했더니 onFocus 이벤트로 제어는 무사히 완료되었으나 반면 onBlur 이벤트는 입력하고자 하는 키워드를 클릭했을 때도 발생, 클릭한 키워드의 값이 input창에 들어가지 않는 문제가 생겼다.
onSubmit이 일어났을 때 표시 상태를 false값으로 변경, onSubmit을 하지 않고 키워드창을 닫고 싶은 경우를 위해 false값으로 변경하는 버튼을 임의로 추가.
input과 키워드 li를 제외한 곳을 클릭했을 때에만 false값으로 바꾸는 방법을 더 찾아볼 것.

Redux-toolkit 적용 오류

리덕스의 사용 방법을 익히기 위해, 사용하는 데이터가 적은 편인 해당 프로젝트에 리덕스를 적용시켜보았다.(원래라면 이렇게 작은 프로젝트에는 리덕스를 사용할 필요가 없으며, 오히려 지나친 사용이다.)
공식페이지에도 나와있는 제일 기초적인 예시인 counter를 참고 삼아 진행 중, dispatch를 통해 action을 실행시키는 곳에서 자꾸 오류가 발생했다.

// 오류가 난 코드

// dataSlice.js
import { createSlice } from '@reduxjs/toolkit';
const dataSlice = createSlice({
  name: 'dataSlice',
  initialState: { answer: '', image: '' },
  reducer: {
    set: (state, action) => {
      console.log(action.payload);
      state.answer = action.payload;
      state.image = action.payload.image;
    },
  },
});

export default dataSlice;
export const { set } = dataSlice.actions;

// App.js
function App() {
  const dispatch = useDispatch();
  const answer = useSelector((state) => {
    return state.data.answer;
  });
  const urlImg = useSelector((state) => {
    return state.data.image;
  });
  const getData = async () => {
    let temp = await getDataAPI();
    dispatch(set({ answer: temp.answer, image: temp.image }));
  };
  return (
    ...
  )
}

오류 메시지를 보면 set이 함수가 아니기 때문에 문제가 발생했다는데 dataSlice.js의 해당 부분을 보면 제대로 함수 형식을 띄고 있다.
오류 메시지에 나온 대로 redux-toolkitis not a function 키워드로 검색. reducers를 reducer로 잘못 적은 탓에 해당 함수를 인식하지 못하는 문제였다.

const dataSlice = createSlice({
  name: 'dataSlice',
  initialState: { answer: '', image: '' },
  reducers: { // 해당 부분을 reducer에서 reducers로 변경.
    set: (state, action) => {
      console.log(action.payload);
      state.answer = action.payload;
      state.image = action.payload.image;
    },
  },
});

타입스크립트 문법을 사용하는 프로젝트(todo)에 해당 코드를 입력해봤더니 바로 에러코드가 발생했다. 어째서 타입스크립트를 선호하게 되는지 몸으로 알게 되었던 오류.

업데이트 예정

  • 자동 완성 키워드
  • 시멘틱 요소 적용하기 03.04
  • Redux-toolkit 적용 04.11
  • 반응형 CSS 적용하기
  • 불러오는 이미지가 늦게 로딩되는 문제
  • 같은 질문을 연달아 하면 씹히는 문제
  • 검색 기록 남기기(필요한가 여부에 따라 선택, 아직 미정)
profile
꾸준히 나아가는 개발자입니다.

0개의 댓글