아직은 리액트 코드를 짜는 순서라던지 과제를 진행하는 순서들이 조금 헷갈리고 버벅거리는 느낌이라 정리하기!
집사 용어 사전 링크
사전 만들기로 과제가 주어져서 기획이랄건 없지만..!
이왕 만드는거 '과제니까 해야한다..!'의 느낌이 아닌 조금 더 즐겁게 해보고자 집사로써 자주 쓰는 단어로 사전을 만들어보자! 했다 ㅎㅎ
만들기 전에 노트에 한 번 적어보고 구현해야하는 기능을 위한 액션이나 데이터 리스트 값들을 정리해 보았다!
그럼 이제 시작!
<Switch>
<Route path='/' exact component={Board}/>
<Route path='/write' exact component={Write}/>
<Route path='/edit/:index' exact component={Edit}/>
</Switch>
☝🏻 수정 페이지는 각 게시글의 인덱스로 구분하여 넘겨주었다.
시간이 조금 남아서 기획에는 없었던 수정 기능도 구현해서 포함되어있음!!
리덕스 데이터 사용하기
1) 액션(action) / 액션 호출 함수(action creators) / 리듀서(reducer)
2) store 만들기
3) index js와 연결하기 - Provider로 store 연결하기
4) 적용하여 사용하기
firebase
1) 파이어베이스 통신 함수 만들기
2) 적용하여 사용하기
순서 이해하기 : 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>
...
순서 이해하기 : 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>
...
순서 이해하기 : 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>
...
순서 이해하기 : 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>
...