본문 바로가기
코드스테이츠 FE 43기 도전기/실습

React Custom Component

by Dongholy 2023. 2. 21.

Bare minimum Requirement 

Modal, Toggle, Tab, Tag 컴포넌트를 구현합니다.

 

 

1. Modal

useState로 컴퍼넌트에서 상태를 관리 할 수 있습니다.

const [<상태 값 저장 변수>, <상태 값 갱신 함수>] = useState(<상태 초기 값>);

  const [isOpen, setIsOpen] = useState(false);

  const openModalHandler = () => {
    // TODO : isOpen의 상태를 변경하는 메소드를 구현합니다.
    setIsOpen(!isOpen);
  };

 

삼항연산을 이용을 하여 열린상태(isOpen) 일 때 : 아닐 때 를 해주었습니다.

    condition ? exprIfTrue(true) : exprIfFalse(false)
{/* TODO : 조건부 렌더링을 활용해서 Modal이 열린 상태(isOpen이 true인 상태)일 때는 ModalBtn의 내부 텍스트가 'Opened!' 로 Modal이 닫힌 상태(isOpen이 false인 상태)일 때는 ModalBtn 의 내부 텍스트가 'Open Modal'이 되도록 구현해야 합니다. */}
{isOpen ? "Opened!" : "Open Modal"}

 

 

똑같이 삼항연산을 이용하여 true 일 때 openModalHandler 를 클릭 할 시(onClick)

ModalBackdrop(Modal이 떴을 때의 배경을 깔아주는 역할) 과 .ModalView(Modal창 컴포넌트) 가 뜰 수 있게 만들어 주었습니다.

false 일 경우는 아무것도 안뜨기 때문에 "" 를 주었습니다.

{/* TODO : 조건부 렌더링을 활용해서 Modal이 열린 상태(isOpen이 true인 상태)일 때만 모달창과 배경이 뜰 수 있게 구현해야 합니다. */}
{isOpen ? (
          <ModalBackdrop onClick={openModalHandler}>
            <ModalView onClick={(event) => event.stopPropagation()}>
              <button onClick={openModalHandler}>X</button>
              <div>HELLO CODESTATES!</div>
            </ModalView>
          </ModalBackdrop>
        ) : null}

 

JS 코드

export const Modal = () => {
  const [isOpen, setIsOpen] = useState(false); // 열려있는지 닫혀있는지 상태

  const openModalHandler = () => {
    // TODO : isOpen의 상태를 변경하는 메소드를 구현합니다.
    setIsOpen(!isOpen); //boolean 값
  };

  return (
    <>
      <ModalContainer>
        <ModalBtn onClick={openModalHandler}>
        {/* // TODO : 클릭하면 Modal이 열린 상태(isOpen)를 boolean 타입으로 변경하는 메소드가 실행되어야 합니다. */}
        {isOpen ? "Opened!" : "Open Modal"}
  
          {/* Open Modal */}
          {/* TODO : 조건부 렌더링을 활용해서 Modal이 열린 상태(isOpen이 true인 상태)일 때는 ModalBtn의 내부 텍스트가 'Opened!' 로 Modal이 닫힌 상태(isOpen이 false인 상태)일 때는 ModalBtn 의 내부 텍스트가 'Open Modal'이 되도록 구현해야 합니다. */}
        </ModalBtn>
        {/* TODO : 조건부 렌더링을 활용해서 Modal이 열린 상태(isOpen이 true인 상태)일 때만 모달창과 배경이 뜰 수 있게 구현해야 합니다. */}
        {isOpen ? (
          <ModalBackdrop onClick={openModalHandler}>
            <ModalView onClick={(event) => event.stopPropagation()}>
              <button onClick={openModalHandler}>X</button>
              <div>HELLO CODESTATES!</div>
            </ModalView>
          </ModalBackdrop>
        ) : null}
      </ModalContainer>
    </>
  );
};

// 자식 요소에서 이벤트가 발생했을 때,
// 부모 요소에서도 같은 이벤트가 발생한 것처럼 동작
// => 이벤트 버블링
// 막기위해서는 ? event => event.stopPropagation()

 

 

2.Toggle

 JS 코드

export const Toggle = () => {
  const [isOn, setisOn] = useState(false);

  const toggleHandler = () => {
    // TODO : isOn의 상태를 변경하는 메소드를 구현합니다.
    setisOn(!isOn);
  };

  return (
    <>
      <ToggleContainer onClick={toggleHandler}
        // TODO : 클릭하면 토글이 켜진 상태(isOn)를 boolean 타입으로 변경하는 메소드가 실행되어야 합니다.
      >
        {/* TODO : 아래에 div 엘리먼트 2개가 있습니다. 각각의 클래스를 'toggle-container', 'toggle-circle' 로 지정하세요. */}
        {/* TIP : Toggle Switch가 ON인 상태일 경우에만 toggle--checked 클래스를 div 엘리먼트 2개에 모두 추가합니다. 조건부 스타일링을 활용하세요. */}
        <div className={`toggle-container ${isOn ? 'toggle--checked' : ''}`} />
        <div className={`toggle-circle ${isOn ? 'toggle--checked' : ''}`} />
      </ToggleContainer>
      {/* TODO : Desc 컴포넌트를 활용해야 합니다. */}
      {/* TIP:  Toggle Switch가 ON인 상태일 경우에 Desc 컴포넌트 내부의 텍스트를 'Toggle Switch ON'으로, 그렇지 않은 경우 'Toggle Switch OFF'가 됩니다. 조건부 렌더링을 활용하세요. */}
      {isOn ? <Desc>Toggle Switch ON</Desc> : <Desc>Toggle Switch OFF</Desc>}
    </>
  );
};

 

 

3. Tab

JS 코드

export const Tab = () => {
  // TIP: Tab Menu 중 현재 어떤 Tab이 선택되어 있는지 확인하기 위한
  // currentTab 상태와 currentTab을 갱신하는 함수가 존재해야 하고, 초기값은 0 입니다.
  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) => {
    // TIP: parameter로 현재 선택한 인덱스 값을 전달해야 하며, 이벤트 객체(event)는 쓰지 않습니다
    // TODO : 해당 함수가 실행되면 현재 선택된 Tab Menu 가 갱신되도록 함수를 완성하세요.
    setCurrentTab(index);
  };

  return (
    <>
      <div>
        <TabMenu>
          {/*TODO: 아래 하드코딩된 내용 대신에, map을 이용한 반복으로 코드를 수정합니다.*/}
          {/*TIP: li 엘리먼트의 class명의 경우 선택된 tab 은 'submenu focused' 가 되며, 
                  나머지 2개의 tab은 'submenu' 가 됩니다.*/}
          {/* <li className="submenu">{menuArr[0].name}</li>
          <li className="submenu">{menuArr[1].name}</li>
          <li className="submenu">{menuArr[2].name}</li> */}
          {menuArr.map((el, index) => {
            return (
              <li
              key={index} // 데이터가 가진 고유값을 key 값으로 설정
              className={currentTab === index ? 'submenu focused' : 'submenu'}
              onClick={() => selectMenuHandler(index)}>
              {el.name}
              </li>
              
            )
          })}
        </TabMenu>
        <Desc>
          {/*TODO: 아래 하드코딩된 내용 대신에, 현재 선택된 메뉴 따른 content를 표시하세요*/}
          {/* <p>{menuArr[0].content}</p> */}
          <p>{menuArr[currentTab].content}</p>
        </Desc>
      </div>
    </>
  );
};

 

 

4. Tag

JS 코드

export const Tag = () => {
  const initialTags = ['CodeStates', 'kimcoding'];

  const [tags, setTags] = useState(initialTags);
  const removeTags = (indexToRemove) => {
    // TODO : 태그를 삭제하는 메소드를 완성하세요.
    // filter?
    setTags(
      tags.filter((el,index) => {
        return index !== indexToRemove })
    )

    
  };

  const addTags = (event) => {
    // TODO : tags 배열에 새로운 태그를 추가하는 메소드를 완성하세요.
    // 이 메소드는 태그 추가 외에도 아래 3 가지 기능을 수행할 수 있어야 합니다.
    // - 이미 입력되어 있는 태그인지 검사하여 이미 있는 태그라면 추가하지 말기
    // - 아무것도 입력하지 않은 채 Enter 키 입력시 메소드 실행하지 말기
    // - 태그가 추가되면 input 창 비우기
    let newTag = event.target.value;
    if (!tags.includes(newTag) && newTag !=="") {
      setTags([...tags, newTag]);
    }
  };

  return (
    <>
      <TagsInput>
        <ul id="tags">
          {tags.map((tag, index) => (
            <li key={index} className="tag">
              <span className="tag-title">{tag}</span>
              <span className="tag-close-icon" onClick={()=>removeTags(index)}>
                {/* TODO :  tag-close-icon이 tag-title 오른쪽에 x 로 표시되도록 하고,
                            삭제 아이콘을 click 했을 때 removeTags 메소드가 실행되어야 합니다. */}x
              </span>
            </li>
          ))}
        </ul>
        <input
          className="tag-input"
          type="text"
          onKeyUp={(e) => {
            {
              /* 키보드의 Enter 키에 의해 addTags 메소드가 실행되어야 합니다. */
              return e.key === 'Enter' ? addTags(e) : ""
            }
          }}
          placeholder="Press enter to add tags"
        />
      </TagsInput>
    </>
  );
};

'코드스테이츠 FE 43기 도전기 > 실습' 카테고리의 다른 글

React State & Props  (0) 2023.01.27
React Twittler Intro  (0) 2023.01.20

댓글