프로젝트를 진행하면서 radio를 3개를 사용하는데, 3개중 하나를 기본값으로 입력되도록 설정하고 싶었다. 해당 페이지는 입력했던 값을 수정하는 페이지였기 때문에, 글을 작성했을 때 선택했던 radio의 값이 해당 페이지(수정 페이지)에서 자동으로 선택되어있어야 했다.
해당 기능은 checked 속성만 추가하면 될 줄 알았는데..ㅎ 그건 아니었고.. defaultChecked라는 속성을 추가해야 했다.
defaultChecked 속성 사용
나는 총 3가지의 radio중 하나만 선택되도록 할 것이다.
3가지의 값은 성별무관(0), 남자만(1), 여자만(2)이다.

useState를 사용하여 limitGender를 만들어주는데 기본값으로 아무것도 넣어주지 않는다. 백엔드에서 값을 받기 때문이다. (만약, 넘겨받는 값이 없다면 그냥 원하는 값으로 기본값을 넣어주면 된다.)

각 radio 값마다 부여해준 값(0,1,2)으로 변경하기 위해서 함수를 총 3개를 만들어주었다. (지금 생각해보면 이럴 필요 없이 하나로 하면 됐을 듯 하다.)

onClick 이벤트를 통해서 해당 input 부분이 클릭되면 선택한 값(0,1,2)으로 limitGender이 변경된다.
그리고 각 radio 태그마다 삼항연산자를 사용하여 defaultChecked를 부여해줬다. 값이 0이라면 0 radio 부분에 limitGender === 0
의 조건이 성립하므로 defaultChecked가 true가 된다.
이때, 다른 radio들은 조건이 성립하지 않으므로 빈 중괄호만 들어간다. (즉, defaultChecked 속성이 들어가지 않는다는 것)
참고
React input radio default checked 설정(리액트 radio 기본값)
input 태그에 value 속성을 추가하면 값이 입력되지 않는 에러가 발생했다. 해당 에러는 React에서만 발생하는 것 같다.
value 속성만이 값을 컨트롤할 수 있는 권한이 존재하기 때문에 사용자가 값을 변경할 수 없다. 따라서 onChange를 사용하여 값이 변경되도록 한다.
onChange를 사용하여 에러 해결

값이 변경되는 것을 반영하기 위해서 useState를 사용한다.

값이 변경될 수 있도록 handelMeetingTime이라는 함수를 만들어 준다. 해당 함수가 실행되면 setMeetingTime으로 meetingTime의 값이 변경된다.
이때, 변경될 값은 e.target.value
이다. 현재 타겟팅 되어있는 값으로 변경하는 것이다.

onChange 이벤트를 사용하여 변화가 감지되면 handleMeetingTime 함수가 실행된다. 그리고 변경된 값이 input에 잘 나타나도록 value에 meetingTime을 넣어주면 된다.
참고
input 엘리먼트에 value 속성만 지정했을 때 값이 입력불가한 현상 해결방법
지난편에 이어 selectBox 구현 글을 작성하겠다.
이번편이 굉장히.. 날 고통스럽게 만들었던 부분이다.
해당 편에서 구현해야 할 기능
- 선택한 값을 select(
.sbtn-select
)에 띄우기
- ButtonSelect 컴포넌트를 사용하는 페이지(CourseList)에 선택한 값들이 추가 박스(
.cl-location
)로 나타나게 하기
미리 보는 완성된 영상

.sbtn-select
에 선택한 값 띄우기
선택한 값이 들어갈 span 태그 .sbtn-select
를 만들어주고, useState로 selectValue를 만든다.
저번편에 li태그 값들을 뿌려줬던 해당 코드에서 li태그 부분에 onClick 이벤트를 추가한다.
onClick 이벤트에 setSelectValue(`${it.item}`)
를 넣어준다. 해당 코드는 li태그를 클릭하면 selectValue를 it.item
값으로 변경해준다는 의미이다.
자, 그러면 원하는 li태그를 클릭했다면 해당 li 태그의 값이 selectValue에 들어가게 된다. 그러면 .sbtn-select
에 selectValue 값을 넣어주면, 우리가 선택한 값이 띄워지게 되는 것이다.
여기서 추가로, html의 select 태그의 경우에는 값을 선택하기 전에 기본적으로 띄워주는 값을 설정할 수 있다. 그래서, 나도 해당 기능을 추가해주기로 했다.
ButtonSelect에 title이라는 props를 추가하여 부모 요소(CourseList)에서 title의 값을 받아준다. 해당 title이 값을 선택하기 전에 기본적으로 띄워줄 값이다.
.sbtn-select
에서 삼항연산자를 통해 selectValue의 값이 있다면 selectValue를 뿌려주고, 값이 없다면(즉, 빈배열이라면) title값을 뿌리도록 해줬다.

.sbtn-select
에 말줄임 표시
.sbtn-select
에 들어오는 값이 너무 길면 말줄임 표시를 해주도록 했다.
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
white-space:nowrap
을 통하여 자동으로 줄바꿈하는 것을 막아준다.
그리고 overflow:hidden
을 통해 지정한 박스 사이즈를 넘어가게 되면 잘라준다.
text-overflow:ellipsis
를 통해 넘어간 부분을 말줄임표(…) 처리가 되도록 한다.
자식에서 부모로 값 전달하기
우리가 props를 사용할때 대부분 부모에서 자식요소로 값을 전달해준다. 그러나 나는 자식에서 부모로 값을 전달해야 하는 경우가 발생했다.
여기서 부모는 CourseList, 자식은 ButtonSelect이다.
CourseList는 page인데, 위의 완성 영상을 보면 값을 선택하면 select 박스 옆에 선택한 값의 박스(.cl-location
)가 나타나야한다.
우리는 선택한 값을 자식에서만 다루는데, 이 자식에서 선택한 값을 부모로 보내서 해당 페이지(CourseList)에 작은 박스로 뿌려주도록 해야한다.
여튼, 결론은 자식에서 부모로 값을 전달해야 한다는 것
일단, 부모에 getTextValue(text)라는 함수를 만들어 준다. 그리고 자식에 props를 getTextValue를 만들어서 전달하는 값으로 getTextValue를 넘겨준다. 자식에게 해당 함수가 부모에 존재한다고 알려주는 것이다.
그리고 자식에서 해당 함수를 실행시켜 준다. 이때, 우리는 참고한 글과 는 조금 다르게 실행시킨다. useEffect를 사용해주는 것이다.
참고한 글 처럼 sendTextValue 함수(부모로 값 전달하는 함수)를 만들어서 실행시켜줘도 된다. 해당 방법으로 코드를 작성하면 li 태그의 onClick 이벤트가 실행되면서 sendTextValue 함수가 실행된다.
그러나 이 방법은 선택한 값이 select의 .sbtn-select
는 바로 적용되지만 .cl-location
에는 한 박자 늦게 적용된다.
내가 가장 처음 1을 선택하면 .cl-location
은 나타나지 않는다. 그 다음에 2를 선택해야 .cl-location
에 1 값이 나타나게 된다.
이런 기능적인 오류가 발생하는 이유를 추측하기로는 onClick에 두개의 함수(getTextValue랑 setSelectValue)가 있는데, selectValue 값이 getTextValue랑 동시에 실행돼서 selectValue값이 업데이트 되기 전에 getTextValue가 실행하는 것이 아닐까.. 따라서 값의 변경의 한 박자 느리게 반영된것이 아닐까 추측중이다.
따라서, 해당 기능 오류를 해결하기 위해서 useEffect를 사용해줘야 한다. useEffect로 변화를 바로 감지할 수 있도록 하는 것이다.
useEffect의 deps로 selectValue를 하여 selectValue의 값의 변경을 감지하면 getTextValue함수가 실행되도록 한다.
자식에서 getTextValue(selectValue)를 실행시키도록 해주면, 부모에서 getTextValue 함수가 실행되면서 setTextValue(text)를
(자식에서의 selectValue가 부모의 text에 들어오는 것)
통해 textValue에 값에 text(selectValue)가 들어가게 된다.
해당 코드를 적용하면 textValue가 .cl-location
에 바로 적용된다!
위에 설명한 코드 로직은 다음과 같다.
- 자식에서 값 선택(setSelectValue 실행)
- selectValue의 변화를 useEffect가 감지
- 부모로 값 전달 (getTextValue 실행)
- 부모에서 getTextValue 실행 (setTextValue 실행)
.cl-location
에 textValue 반영
ButtonSelect(자식) 코드는 위에 이미지 참고
CourseList(부모) 코드
주석은 치열한 오류잡기의 흔적..이므로 무시할 것

마치며
select 태그 기능을 직접 구현해봤는데, 처음에 생각한 것 보다는 엄청 어렵지는 않았다. 1편의 부분은 구현하는데 힘들기는 했어도 못할 정도는 아니었는데, 2편의 부분이.. 특히 getTextValue 부분이 정말.. 기능 오류..잡는게 너무 힘들고 어려웠다.. 포기할까 생각도 했지만, 그건 찝찝하고… 그리고 이렇게 오래 붙들고 있었는데 그 시간들이 아까웠달까
그래도 결론적으로는 잘 구현해서 정말 뿌듯했다. 완성한 결과물을 보니.. 그간 고생하고 힘들었던게 싹 사라진달까..
한달 후에 적고 있는 지금도 그때 생각하니 정말 감격스러운 감정이 든다..
해당 기능을 구현하면서 useEffect가 이런 거구나!!를 완벽히 깨달았고, useState 또한 완벽히 이해할 수 있었다.
그전에 강의를 보면서 할때는 useEffect랑 useState는 이런거구나..를 머리로만 이해했는데, 해당 기능을 구현하기 위해 별 자료를 다 찾아보고 내 프로젝트에 맞게 변경하려다보니 해당 기능들을 완벽히 이해할 수 있었다.
이래서.. 개발은 직접 원하는 프로젝트를 진행하면서 공부하라는 말이 이런거구나! 를 깨달았다.
이제 다음번에 select 태그 구현한다면 좀 더 빨리 잘 할 수 있을 것 같다.
참고
부모에서 자식, 자식에서 부모 값 전달하는 방법 prose, function
부모에서 자식, 자식에서 부모 값 전달하는 방법
useEffect 변화의 감지
css에서 텍스트 ellipsis(‘…‘)말줄임 표시 처리하는 방법
알아두면 유용한 잡다한 CSS
들어가는 말 (잡담)
사실 해당 기능은 9월에 진작 끝냈지만 ^^…
9월에 프로젝트 일이 휘몰아치면서 이제야.. 적게 되었다.. (과거의 나 반성해..) 한달 정도 늦게 작성하는 거라 기억이 많이 휘발되었지만, 그 당시에 막혔던 부분들을 복습한다 생각하고 작성해보겠다.
SelectBox 직접 구현하기
html에 select 태그가 존재하지만, 드로맵 프로젝트에서 해당 태그를 사용할 수 없었다. 디자이너 분이 select 박스의 디자인을 이쁘게 만들어주셨는데.. select 태그로는 해당 디자인 구현이 불가능해서 ㅜ… 직접 select 박스를 만들었어야 했다.
기본적인 select 박스의 틀은 해당 영상을 참고하여 구현하였다.
다 만들고 생각했던건데, 굳이? 영상 참고 안하고 해도 됐을 것 같았다. 처음 만든다는 두려움 때문에 참고자료를 찾고 싶어서 고생했던게 기억 난다..
쨋든, select 박스의 틀은 본인이 원하는 디자인으로 만들면 된다.
select 리스트 열고 닫기
나는 select 리스트(li(값)들)를 열고 닫을 수 있도록 img(여닫기 화살표)를 구현해줬다. useState로 isActive를 만들고 기본값은 false(닫힘)으로 했다. 버튼(여닫기) 이미지의 style에 transform: isActive
로 하여, isActive가 false이면 화살표가 아래로, true이면 화살표가 위로 (rotate(-180deg)
)향하도록 했다.
또한, class가 sbtn-content를 보면 display에도 isActive를 주었는데, isActive값이 false이면 none을 (ul 태그가 보이지 않음) true면 block을 (ul 태그가 보임/ 즉, select 리스트 박스가 보임) 해줬다.
map 함수를 사용하여, select list의 li 값 뿌리기
정말 간단하게 그냥 ul 태그 하단에 넣고 싶은 li 값들을 다 쓰면 되겠지만! 해당 selectBox 컴포넌트는 여러 페이지에서 재사용이 필요하기 때문에 map 함수를 이용하여 값들을 넣어주기로 했다.
추후에 백엔드로부터 해당 select에 넣을 값 리스트를 받기만 하면 되도록 말이다!

따라서 나는 일단 dataList
라는 배열 변수를 만들어줬다.
해당 배열 안에 key는 item이고 value에는 원하는 값들을 넣은 객체를 만들어줬다.
그리고 ul 태그 하단에 dataList
를 map함수를 통해 뿌려줬다.
이때, map은 함수니까 꼭! 중괄호{}
로 감싸야 한다는 것을 잊지 말자.
중괄호 안에 dataList.map((it)=>{return(<li>{it.item}</li>)})
코드를 작성했다. dataList 배열을 map을 통해서 반복을 할건데, li 태그의 값(?)에 it.item을 넣어준다. 라는 것이다.
Error 발생, expected an assignment or function call and instead saw an expression
위의 설명한 방법으로 했을 때는 에러가 발생하지 않겠지만.. 과거에 작성했을 때는 중괄호 안에 return을 작성하지 않았다. 그러니 expected an assignment or function call and instead saw an expression.
에러가 발생했다.
에러가 발생한 이유는 map을 사용할 때, .map(()=>{})
형식으로 작성했다면 반드시 중괄호 안에 return이 존재해야 한다는 것이었다.
만약에 return을 작성하고 싶지 않다면 요소를 소괄호()
로 감싸도록 하자. dataList.map((it)=>(<li>{it.item}</li>))


우리 디자이너가 스크롤바 역시도 이쁘게 디자인해줬기 때문에 스크롤바 스타일 역시 변경해야 했다.
스크롤바 스타일은 -webkit-scrollbar
를 통해 변경해준다.
스크롤바 변경 webkit의 의미는 다음과 같다
다음 속성들을 적용하여 스크롤바를 변경해주었다.

스크롤바 위치 변경
스크롤바 커스텀을 하고 나서도 스크롤바의 위치가 너무 오른쪽에 붙어있어, 해당 바를 좀 더 왼쪽으로 옮겨주고 싶었다.
이때 좀 바보짓을 했는데…ㅋ
박스에 패딩을 주고 뭐 별 짓을 다 했는데도 스타일 적용이 안돼서.. 애먹고 있다가, “다시 스크롤바의 위치가 어디일지를 보자” 란 생각이 들어 다시 개발자도구를 통해 확인해보니 ul 태그에 해야 할 것 같은 것이다…! 그래서 ul태그에 margin을 주었더니 스크롤바의 위치가 안 쪽으로 이쁘게 잘 들어갔다..ㅎ..
결론: 스크롤바 위치를 옮기고 싶으면 ul태그에 margin 주기… 잊지말것..
스크롤바 위치 수정 전

스크롤바 위치 수정 후

스크롤바 수정 전/후 영상

다음 편에는 선택한 값을 띄워주는 것을 작성하도록 하겠다.
참고
HTML, CSS: 스크롤바 스타일(디자인)하는 방법 - webkit-scrollbar > Css 브라우저 스크롤바 스타일 지정, 바꾸는 방법 알아보기
🌟 스크롤 바(Scrollbar) 스타일링 💯 총정리
리액트: 버튼 클릭시 요소 표시, 숨기기 >React hooks로 Select Option 처리하기
React:expected an assignment or function call and instead saw an expression.
React에서 (api 데이터) json형식 데이터 가져오기 및 원하는 데이터 추출 등 데이터 관리 방법!
Webpack & Babel
Webpack?
오픈 소스 자바스크립트 모듈 번들러(여러개를 합쳐주는 것)로, 여러개로 나눠져 있는 파일들을 하나의 자바스크립트 코드로 압축하고 최적화하는 라이브러리이다.

Webpack의 장점
-
여러 파일의 자바스크립트 코드를 압축하여 최적화 할 수 있어 로딩에 대한 네트워크 비용을 줄일 수 있다.
-
모듈 단위로 개발이 가능하여, 가독성과 유지보수가 쉽다.
모듈 단위로 개발의 말은, 한가지 파일에 모든 것들을 넣어두는 것이 아닌 파일을 여러개로 나눠서 Webpack으로 뭉쳐(번들)주는 것을 말한다. 파일을 나눴기 때문에 가독성이 올라가고 유지보수가 쉬워지는 것이다.
Babel?
최신 자바스크립트 문법을 지원하지 않는 브라우저를 위해서 최신 자바스크립트 문법을 구형 브라우저에서도 사용할 수 있게 변환시켜주는 라이브러리이다.
Creat-React-App
CRA는 Webpack이나 Babel을 따로 설치하지 않아도 알아서 설치하고 설정해주는 것이다.
npx creat-react-app <폴더명>
# 혹은 cra를 설치하고 싶은 폴더로 이동
npm creat-react-app ./
npx??
노드 패키지 실행을 도와주는 도구이다. CRA는 npm 레지스트리(registry)에 있는 패키지를 우리의 폴더에서 실행해서 리액트를 설치해준다.
npm 레지스트리(라이브러리가 저장된 곳) ⊃ CRA 패키지 → npx를 통해 CRA 설치 npx creat-react-app ./
→ 우리가 사용할 폴더