Shall We Code의 기능중에 제일 중요한 건 필터링 기능이었다
기획을 끝나고 난 뒤 3월4일에 본격적으로 코드를 작성하기 시작했고
발표날을 빼면 남은시간은 주말포함 6일이었다
글 작성 페이지와 메인 페이지 두곳에 필터링 기능이 존재하는데
결국 필터링이라는 기능은 똑같지만 디자인이 완전히 달랐기 때문에
두가지 전부 구현하기에는 시간이 부족하다고 판단했다
우리가 만들어야 할 페이지가 일곱개나 있었다...!!!
글쓰기 페이지의 필터링 기능은 react-select 를 사용해서 만들었고 메인페이지의 필터링은 직접 구현했다
먼저 react-select를 사용하면서 맞이했던 오류에 대해서 알아보자...
react-select를 글쓰기 페이지에 가져다 넣는 것은 쉬웠다
하지만 이곳에서 사용자가 원하는 기술 스택을 선택 했을 때
그 스택의 데이터만 뽑아서 전달해줘야 했는데 찍어보니 콘솔에 무수한 함수들이 나왔고...
함수들 중에 getValue함수를 써서 가져오려 시도 해봤지만 내가 선택한 값의 마지막 값은 출력이 되지 않았다😨
영어만 가득한 공식 홈페이지를 보며 다시 한번 영어공부를 열심히 해야겠다 다짐했다...
구글링 끝에 onChange를 이용해서 값을 가져올 수 있었다
const [stack, setStack] = useState({languageList})
const handleChangeStack = e => {
let stackLanguageList = []
e.map((v,i)=>{stackLanguageList.push(v.value)})
setStack(stackLanguageList)
}
....
<Select
isMulti
name="colors"
options={languageList}
className="basic-multi-select"
classNamePrefix="select"
placeholder={"프로젝트 기술 스택 선택"}
onChange={(e) => handleChangeStack(e)}
> </Select>
메인페이지의 필터 디자인은 이렇게 원하는 스택의 버튼을 클릭했을 때 버튼의 색이 변하고 선택한 버튼의 값만 출력이 가능해야 했다
그래서 languages라는 배열에 사용하는 언어들을 다 넣어둔 뒤
languages에 map을 돌려 버튼을 생성했고
그 language를 관리하기 위한 상태를 useState로 만들었다
languageFilter가 선택한 languages를 포함하고 있는지에 따라서 removeLanguage , setLanguage 함수를 실행하고 클래스 네임을 추가해 버튼에 색을 더해줬다
const languages = [
{ value: "01", label: "JavaScript" },
{ value: "02", label: "TypeScript" },
{ value: "03", label: "React.js" },
.....
{ value: "13", label: "Swift" },
{ value: "14", label: "Python" }
];
const [languageFilter, setLanguageFilter] = useState([]);
const languagesOnClick = (language) => {
languageFilter.includes(language)
? removeLanguage(language)
: setLanguage(language)
};
const setLanguage = (language) => {
setLanguageFilter([...languageFilter, language]);
};
const removeLanguage = (language) => {
const index = languageFilter.findIndex((lan) => lan === language);
languageFilter.splice(index, 1);
setLanguageFilter([...languageFilter]);
};
{languages.map((language,i) => {
return <button
key = {i}
onClick={()=>{languagesOnClick(language.value)}}
className={`${languageFilter.includes(language.value) ? "active miniBtn filterMiniBtn" : "miniBtn filterMiniBtn"}`}
>{language.label}</button>
})}
원래의 기획은 원하는 프로필 사진을 올려서 적용 할 수 있게
만들려고 했지만 서버에 요청, 적용하는 과정에서 오류가 잡히지 않았다
시간이 부족한 관계로 기본 사진을 네개 정해놓고 그 중에서만 선택 할 수있게 하는 걸로 기획을 변경했다
const [curImg, clickImg] = useState("/images/1.png");
const handleProfileClick = (e) => {
let img = e.target.src.slice(e.target.src.length - 13)
clickImg(img)
}
const handleProfileSelect = () => {
axios.patch('http://localhost:4000/users/pictureEdit', {picture: curImg})
.then((res)=>{
if(res.status === 200){
window.location.replace('/Setting')
}
}).catch((err)=>{
console.log(err);
})
}
....
return(
....
<img className="profileBigImg" value = "1" src={curImg}/>
<button className="miniBtn smallSizeFont newProfileBtn" onClick={handleProfileSelect}>이미지 적용</button>
....
<div className="profileMiniImgDiv">
<img onClick={handleProfileClick} className="profileMiniImg" src="/images/1.png"/>
<img onClick={handleProfileClick} className="profileMiniImg" src="/images/2.png"/>
<img onClick={handleProfileClick} className="profileMiniImg" src="/images/3.png"/>
<img onClick={handleProfileClick} className="profileMiniImg" src="/images/4.png"/>
</div>
)
이렇게 코드를 짜고 나니 선택한 이미지로 실제 프로필에는 적용이 되는데 바로 위의 큰 이미지는 변경이 되지 않았다
시간이 부족해서 팀원분한테 도움을 요청했고 userinfo가 있을 때
curImg 이미지를 변경시켜주는 걸로 해결을 해주셨다
useEffect에 대한 공부가 더 필요하다고 다시 느꼈다
const { userinfo } = props
useEffect(() => {
if (userinfo) {
clickImg(userinfo[0].picture)
}
},[userinfo])
회원탈퇴를 하고나면 메인페이지로 이동하게 되는데 이때 새로고침을 하지 않으면 로그인 상태가 풀리지 않는 상황이 발생했다
로그인 상태 관리는 app.js에서 관리하고 있고
handleResponseSuccess를 로그인페이지에 넘겨줘서
로그인 버튼을 누를때 실행시키는 방식으로 사용하고 있다
그리고 useEffect를 통해 페이지가 렌더링 될 때마다 isAuthenticated 유저 인증정보를 불러와 로그인 상태를 유지, 변경시켜주고 있다
그냥 history.push로 넘어가게 된다면 페이지가 랜더링 되지 않아서 window.location.replace("/")으로 페이지를 강제 랜더링 시켜줬다
const [isLogin, setIsLogin] = useState(false);
const [userinfo, setUserinfo] = useState(null);
const isAuthenticated = () => {
axios.get('http://localhost:4000/users/auth')
.then(data => {
if (data.status === 200) {
setUserinfo(data.data.data.data)
setIsLogin(true)
}
})
.catch(err => console.log("주 에러 : ",err))
};
const handleResponseSuccess = () => {
isAuthenticated()
};
useEffect(() => {
isAuthenticated()
}, []);
처음 기획단계에서 사용해야 하는 데이터를 고려하지 않은 컴포넌트 설계가 상태를 관리하기 힘들게 만들었다
다음 프로젝트에서는 기획단계에서 더욱 더 자세하게 짚고 넘어가야 될 것들이 많다는 것을 깨달았다
섹션 1,2,3보다 2주 프로젝트에서 배운 것이 훨씬 많은 것 같고 재밌었다
잠을 3시간 자도 아 이거 완성해야되는데 하면서 빨리 일어나게 됐고
진짜 해결이 안될 때는 잠깐 쉬어야 한다는 것도 깨달았다
잠시 쉬다보면 떠오르지 않았던 아이디어가 생각나기도 했다
다시 한번 좋은 팀원들을 만나서 행복했고
파이널 프로젝트에서는 영혼을 갈아넣어서 완성시켜봐야겠다