const Container
const ModalBtn
const Overlay
const ModalView
//1. Modal 컴포넌트 : 모달창이 열려있는지 닫혀있는지에 대한 상태.
//모달창은 처음에는 닫혀있어야하기때문에 초기값으로 false를 준다.
const Modal = () => {
const [isOpen, setIsOpen] = useState(false);
//2. setIsOpen()을 사용해 isOpen의 상태를 변경한다.
//! 연산자를 사용해 이벤트가 발생할때마다 현재값과 반대값이 들어가도록 함
const openModal = () => { setIsOpen(!isOpen) }
return (
<div>
<Container>
<ModalBtn
onClick={openModal} //3. 클릭하면 이벤트 실행
>
//4. 삼항연산자로 조건부 렌더링. isOpen이 true면 전자, false면 후자가 실행되어 버튼 콘텐츠가 바뀐다.
{isOpen ? "Opened" : "Open Modal"}
</ModalBtn>
{isOpen ?
//3. true면 오버레이를 줌. 오버레이 클릭하면 모달창을 닫는다.
<Overlay onclick={openModal}>
<ModalView //이벤트버블링을 막기 위한 코드
onClick={(e) => e.stopPropagation()}>
<button //3. x클릭하면 모달창을 닫는다
onClick={openModal}>x</button>
</ModalView>
</Overlay>
}
: null //아무것도 안뜸
</Container>
</div>
)
}
더 생각해봐야 할 것
모달이 열린 상태에서 스크롤을 멈춰야 함.
시도해본것 1. 조건에 따라 클래스네임을 주기 2. useEffect
1은 전체 컨테이너(root)에 클래스네임을 줘야 기능할 것 같다.
2는 스크롤을 막긴 하는데 모달창이 안열려있어도 스크롤이 안되는 문제가 생김.
const Container
const ToggleBody = styled.div`
&.checked { 대충 체크됐을때 나타낼 css1}
`
const ToggleBtn = styled.div`
&.checked { 대충 체크됐을때 나타낼 css2}
`
const Toggle = () => {
//1. useState로 on/off상태 구현
const [isOn, setIsOn] = useState(false);
const toggleOn = () => {
setIsOn(!isOn); //! 현재와 반대값 할당
}
return (
<div>
<Container>
//클래스네임도 삼항연산자로 부여 가능
<ToggleBody className={ isOn ? "checked" : "" } />
<ToggleBtn className={ isOn ? "checked" : "" } />
</Container>
</div>
)
}
const TabMenu
const Display
const Tab = () => {
const [currentTab, setCurrentTab] = useState(0);
const menuArr = [{name: 1, content: 1},{name: 2, content: 2},{name: 3, content: 3}]
const selectMenu = (i) => { //index를 전달
setCurrentTab(i)}
return (
<div>
<TabMenu>
{menuArr.map((el, i) =>
return (
<li
className={currentTab === i ? 'focus': ''
//index를 인자로 넘겨야하기때문에 화살표함수 형태로 작성한다. 함수실행하는 형태는xx
onClick={()=> selectMenu(i)}}
>{el.name}</li>))}
</TabMenu>
<Display>{menuArr[currentTab].content}</Display>
</div>
)
}
const Input
const Tag = () => {
const initTags = ['javascript', 'react']
const [tags, setTags] = useState(initTags)
const removeTag = (i) => {
setTags(tags.filter((el, index) => index !== i))
}
const addTag = (e) => {
if(tags.includes(e.target.value) === false
&& e.target.valus === "") {
setTags([...tags, e.target.value]);
} else return "";
//엔터치면 인풋 내 값을 초기화시킴
const emptyValue = () => {
ref.current.value = "";
};
return (
<div>
<Input>
<ul>
{tags.map((tag, i)=> (
<li key={i}>
<TagTitle>{tag}</TagTitle>
<span //index를 넘기기 위해 익명함수 형태로 기재
onClick={()=> {removeTag(i)}}>x</span>
</li>
))}
</ul>
<input
onKeyUp={(e)=>{
return e.key === 'Enter' ?
(
addTags(e) //두가지 이벤트를 실행하려면 소괄호로 묶고 쉼표로 구분해준다.
, emptyValue()): null
}}
/>
</Input>
</div>
)
}
useRef를 사용해서 태그가 있건 없건 엔터를 쳤을때 인풋창을 비우도록 해주었다. 이 비우는 걸 해주면 테스트는 통과하지 못하지만...ㅎ 여턴간 비워주는 게 유저경험에 좋을거라 생각함