[Project] - 항해99 React 기본 과제 회고

니나노개발생활·2021년 7월 1일
0

🦾성장통

목록 보기
26/60
post-thumbnail

아직은 리액트 코드를 짜는 순서라던지 과제를 진행하는 순서들이 조금 헷갈리고 버벅거리는 느낌이라 정리하기!
집사 용어 사전 링크

기획


사전 만들기로 과제가 주어져서 기획이랄건 없지만..!
이왕 만드는거 '과제니까 해야한다..!'의 느낌이 아닌 조금 더 즐겁게 해보고자 집사로써 자주 쓰는 단어로 사전을 만들어보자! 했다 ㅎㅎ
만들기 전에 노트에 한 번 적어보고 구현해야하는 기능을 위한 액션이나 데이터 리스트 값들을 정리해 보았다!
그럼 이제 시작!

코드 진행 순서

1. 뷰 만들기

  • 메인 보드
  • 단어 추가 페이지
  • 단어 수정 페이지(우선은 뷰만 만들었고 내용은 기능 구현해서 가져오는 데이터)

2. 라우팅

<Switch>
        <Route path='/' exact component={Board}/>
        <Route path='/write' exact component={Write}/>
        <Route path='/edit/:index' exact component={Edit}/>
</Switch>

☝🏻 수정 페이지는 각 게시글의 인덱스로 구분하여 넘겨주었다.

3. 기능 추가

시간이 조금 남아서 기획에는 없었던 수정 기능도 구현해서 포함되어있음!!

리덕스 데이터 사용하기

1) 액션(action) / 액션 호출 함수(action creators) / 리듀서(reducer)
2) store 만들기
3) index js와 연결하기 - Provider로 store 연결하기
4) 적용하여 사용하기

firebase

1) 파이어베이스 통신 함수 만들기
2) 적용하여 사용하기

load

순서 이해하기 : FB - Action Creators - Action - Reducer - js

  • 액션
const LOAD_DICT = 'dict/LOAD_DICT';
  • 액션 호출 함수
export const loadDict = (dict) => {
  return {type: LOAD_DICT, dict}
}
  • 파이어베이스 통신 함수
export const loadDictFB = () => {
  return function(dispatch) {
    dict_db.get().then((docs) => {
      let dict_data = [];
      docs.forEach((doc) => {
        if(doc.exists){
          dict_data = [...dict_data,{id:doc.id, ...doc.data()}];
        }
      })
      dispatch(loadDict(dict_data));
    });
  }
}
  • 리듀서
case 'dict/LOAD_DICT': {
      let dict_data = [...state.list];

  	//데이터값은 id로 구분
      const dict_ids = state.list.map((r,idx) => {
        return r.id;
      });
      const dict_data_fb = action.dict.filter((r,idx) => {
        if(dict_ids.indexOf(r.id) === -1) {
          dict_data = [...dict_data,r];
        }
      });
      return {...state, list: dict_data}
    };
  • 적용시키기
...
const _list =useSelector((state) => state.dict.list);

  console.log(_list)

	//강의에서는 클래스형으로 나타내어 DidMount에 파이어베이스 로드하는 부분이 들어가는데 함수형으로 나타내었으니 useEffect를 사용하여 파이어베이스와 통신 >> 파이어베이스의 데이터 내용을 뷰에 로드하기 위한 작업 + [] 부분은 무한 루프를 막아줌
  React.useEffect(() => {
    dispatch(loadDictFB());
  }, []);

  return (
    <Wrap>
      <BoardContainer>
        <Top>
            <LeftPaw src={image}/>
            <h2>집사 용어 사전</h2>
            <RightPaw src={image}/>
        </Top>
        <ScrollBox id='scroll'>
        //_list에서 map을 돌리는 이유는 파이어베이스 안의 데이터를 리덕스에 저장해두었기 때문에 이 리덕스를 소환
          {_list.map((l,idx) => {
            return (
              <BoardLists>
                <List key={idx}>
...
                        <EditBtn
                          key={idx}
                          onClick={() => {
               //수정은 맵으로 돌린 각 리스트의 인덱스값으로 불러와서 해당 인덱스의 id로 글을 판단하여 불러온다
                          props.history.push('/edit/'+idx)
                        }}>
                          수정
                        </EditBtn>

...

add

순서 이해하기 : FB - Action Creators - Action - Reducer - js

  • 액션
const ADD_DICT = 'dict/ADD_DICT';
  • 액션 호출 함수
export const addDict = (dict_data) => {
  return {type: ADD_DICT, dict_data}
}
  • 파이어베이스 통신 함수
export const addDictFB = (input_text) => {
  return function(dispatch) {
    let dict_data = {
      word: input_text.word,
      description: input_text.description,
      example: input_text.example,
    };

    dict_db.add(dict_data).then(docRef => {
      dict_data = {...dict_data, id:docRef.id};
      dispatch(addDict(dict_data));
    })
    .catch((err) => {
      window.alert('오류가 났어요! 나중에 다시 시도해주세요!')
    });
  };
};
  • 리듀서
case 'dict/ADD_DICT': {
      return {...state, list: [...state.list, action.dict_data]}
    }
  • 적용시키기
...
<AddBtn 
        onClick = {() => {
          let input_text = {
            word: input_word.current.value,
            description: input_description.current.value,
            example: input_example.current.value
          }
          dispatch(addDictFB(input_text));
          window.setTimeout(()=> {
            props.history.push("/")
          },500);
        }}>추가하기</AddBtn>
...

delete

순서 이해하기 : FB - Action Creators - Action - Reducer - js

  • 액션
const REMOVE_DICT = 'dict/REMOVE_DICT';
  • 액션 호출 함수
export const removeDict = (dict) => {
  return {type: REMOVE_DICT, dict}
}
  • 파이어베이스 통신 함수
    case 'dict/REMOVE_DICT': {
      const dict_list = state.list.filter((l,idx) => {
        if(idx !== action.dict) {
          return l;
        }
      });
      return {list:dict_list}
    };
  • 리듀서
case 'dict/LOAD_DICT': {
      let dict_data = [...state.list];

      const dict_ids = state.list.map((r,idx) => {
        return r.id;
      });
      const dict_data_fb = action.dict.filter((r,idx) => {
        if(dict_ids.indexOf(r.id) === -1) {
          dict_data = [...dict_data,r];
        }
      });
      return {...state, list: dict_data}
    };
  • 적용시키기
...
<DeleteBtn onClick={() => {
                        dispatch(removeDictFB(idx));
                        }}>삭제
                        </DeleteBtn>
...

update

순서 이해하기 : FB - Action Creators - Action - Reducer - js

  • 액션
const UPDATE_DICT = 'dict/UPDATE_DICT';
  • 액션 호출 함수
//다른 아이들이랑은 다르게 수정을 하려면 해당 글의 인덱스와 수정한 데이터 값이 필요했다.
export const updateDict = (data_index, _dict_data) => {
  return {type: UPDATE_DICT, data_index, _dict_data}
}
  • 파이어베이스 통신 함수
export const updateDictFB = (data_index, input_text) => {
  return function (dispatch, getState) {
    //기존 값을 불러온다.
    const _dict_data = getState().dict.list[data_index];

    //add와 동일하게 새롭게 입력된 인풋 데이터를 가지고 온다.
    let input_data = {
      word: input_text.word,
      description: input_text.description,
      example: input_text.example,
    }
    
    if(!_dict_data.id) {
      return;
    }

    dict_db.doc(_dict_data.id).update(input_data).then((docRef) => {
      input_data = {...input_data, id:_dict_data.id}
      dispatch(updateDict(data_index, input_data));
    })
    .catch((err) => {
      console.log('err')
    });
  };
};
  • 리듀서
    case 'dict/UPDATE_DICT': {
      const update = action._dict_data;
      const dict_list =state.list.map((l,idx) => {
        if(idx === action.data_index) {
          return update;
        } else {
          return l;
        }
      })
      console.log(dict_list)
      return {list: dict_list}
    }
  • 적용시키기
...
onClick = {() => {
          let input_text = {
            word: input_word.current.value,
            description: input_description.current.value,
            example: input_example.current.value
          }
          dispatch(updateDictFB(data_index, input_text));
          window.setTimeout(()=> {
            props.history.goBack()
          },500);
        }}>완료하기</AddBtn>
...

느낀 점

  • 강의 때 예시로 만들었던 버킷리스트와 퀴즈의 코드를 참고하여 과제를 완성할 수 있었다.
    과제를 시작하기 전에 강의를 다 듣고 한 번 정리해보고 그걸 토대로 다시 참고해서 예시를 또 한 번 만들어보고 과제를 시작해서 그런지 과제를 다 완성하는데 하루밖에 걸리지 않아서 조금 뿌듯 ㅎㅎㅎ
    그래서 주어진 기능이었던 데이터를 파이어베이스에 저장하고 새로운 단어를 추가하는 기능에 더해서 단어를 삭제하고 수정하는 기능도 구현해보았다.
    삭제는 같이 강의에서 구현해봐서 기능이 이해가 갔는데 수정은 데이터를 아예 바꿔주는 수정을 진행해보지않아 해당 인덱스를 가지고 뷰를 뿌려주는데 오류..데이터를 받아오는데 오류...다시 적용하는데 오류...다시 뷰에 적용하는데 오류...한 단계 한 단계 나아갈 때마다 오류가 떠서 정말 빨간 화면 파티였다 ㅎㅎㅎㅎㅎ
    그래도 매개변수를 어떻게 주고 하나씩 지워보고 추가해보고 콘솔에 찍어서 진행 단계를 따라가보니 오류도 해결하고 수정 기능도 완성했다!
    많은 코드들을 참고하면서 만들었지만 그래도 돌아가는 과정도 이해할 수 있었고 단계를 뒤따라가니 재미있었다!!
profile
깃헙으로 이사중..

0개의 댓글