[React] UI 컴포넌트 만들기 (styled-components)

young·2022년 7월 1일
0

6/23~7/20 Section 3 TIL

목록 보기
9/21
post-custom-banner

export const Modal = () => {
  //모달창이 열리고 닫힌 상태
  const [isOpen, setIsOpen] = useState(false);
	
  //모달 버튼을 클릭하면 상태를 변경한다
  const openModalHandler = () => {
    setIsOpen(!isOpen);
  };

  return (
    <>
      <ModalContainer>
        <ModalBtn onClick={openModalHandler}>
          {isOpen ? "Opened!" : "Open Modal"}
        </ModalBtn>
        
        {/* 모달이 열린 상태면 ? 배경, 모달창이 열린다 : null */}
        {isOpen ? (
          <>
            <ModalBackdrop onClick={openModalHandler}>
              <ModalView>
                <Btn onClick={openModalHandler}>X</Btn>
                <h2>Hello World</h2>
              </ModalView>
            </ModalBackdrop>
          </>
        ) : null}
      </ModalContainer>
    </>
  );
};

모달 배경(모달창이 오픈 되었을 때의 배경)을 클릭하면 창이 닫히도록 onClick 이벤트를 주었다.

export const ModalBackdrop = styled.div`
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
`;

모달 배경은 화면에 꽉 차도록 position: fixed를 설정해주었다.


Toggle

const Desc = styled.div`
  text-align: center;
  margin: 10px;
`;

export const Toggle = () => {
  //토글의 on, off 상태
  const [isOn, setisOn] = useState(false);

  const toggleHandler = () => {
    setisOn(!isOn);
  };

  return (
    <>
      <ToggleContainer onClick={toggleHandler}
        {/* 토글 ON이면 toggle--checked라는 클래스를 추가해주었다. */}
        <div className={`toggle-container ${isOn ? "toggle--checked" : ""}`} />
        <div className={`toggle-circle ${isOn ? "toggle--checked" : ""}`} />
      </ToggleContainer>
      <Desc>Toggle switch {isOn ? "ON" : "OFF"}</Desc>
    </>
  );
};

styled-components 구현 부분

const ToggleContainer = styled.div`
  position: relative;
  margin-top: 8rem;
  left: 47%;
  cursor: pointer;

  > .toggle-container {
    width: 50px;
    height: 24px;
    border-radius: 30px;
    background-color: #8b8b8b;
  }

  > .toggle-container.toggle--checked {
    background-color: #5055de;
  }

클래스가 입혀졌을 때의 스타일은 > .class명.추가class명 과 같이 작성한다.


Tab

export const Tab = () => {
  //클릭시 변경되는 currentTab의 상태 (index)
  const [currentTab, setCurrentTab] = useState(0);
 
  const menuArr = [
    { name: "Tab1", content: "Tab menu ONE" },
    { name: "Tab2", content: "Tab menu TWO" },
    { name: "Tab3", content: "Tab menu THREE" },
  ];

  const selectMenuHandler = (index) => {
    setCurrentTab(index)
  };

  return (
    <>
      <div>
        <TabMenu>
          
          {/* 클릭한 탭은 focused 클래스가 추가된다*/}
          {menuArr.map((e, i) => (
            <li
              key={i}
              onClick={() => selectMenuHandler(i)}
              className={`${currentTab === i ? "submenu focused" : "submenu"}`}
            >
              {menuArr[i].name}
            </li>
          ))}
        </TabMenu>
        <Desc>
          <h2>{menuArr[currentTab].content}</h2>
        </Desc>
      </div>
    </>
  );
};

array.map()으로 생성한 메뉴 탭 li태그에 onClick 이벤트를 주어서
클릭한 li태그는 해당 탭의 index를 이벤트 핸들러로 넘겨주고
클릭한 index로 상태를 변경한다.


Tag

export const Tag = () => {
  const initialTags = ['초기', '태그'];

  //태그 배열 상태
  const [tags, setTags] = useState(initialTags);
  //input의 onChange 이벤트 상태
  const [value, setValue] = useState();

  //태그 삭제는 filter 함수로 구현했다
  const removeTags = (indexToRemove) => {
    setTags(tags.filter((e, i) => i !== indexToRemove))
  };
  
  const addTags = (event) => {
    // - 이미 입력되어 있는 태그인지 검사하여 이미 있는 태그라면 추가하지 말기
    // - 아무것도 입력하지 않은 채 Enter 키 입력시 메소드 실행하지 말기
    // - 태그가 추가되면 input 창 비우기
    if(event.key === "Enter" && !tags.includes(value) && value ) {
      setTags([...tags, value]);
      setValue();
    }
    else if (event.key === 'Enter' && !value) {
      setValue();
    }
  }

  const onChangehandler = (e) => {
    setValue(e.target.value);
  }

  return (
    <>
      <TagsInput>
        <ul id='tags'>
          {tags.map((tag, index) => (
            <li key={index} className='tag'>
              <span className='tag-title'>{tag}</span>
              <span onClick={() => removeTags(index)} className='tag-close-icon'>
                x
              </span>
            </li>
          ))}
        </ul>
        <input
          className='tag-input'
          type='text'
          onKeyUp={(event) => addTags(event)}
          placeholder='Press enter to add tags'
          onChange={onChangehandler}
          value={value || ''}
        />
      </TagsInput>
    </>
  );
};

input의 value를 value={value}로 설정해주니

Warning: A component is changing an uncontrolled input of type undefined to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

콘솔창에 위와 같은 에러가 나와서 undefined를 다루기 위해 value || ''로 설정해주었다.

profile
즐겁게 공부하고 꾸준히 기록하는 나의 프론트엔드 공부일지
post-custom-banner

0개의 댓글