[React] Custom Components 작동 로직

Hyun Jin·2023년 2월 22일
post-thumbnail

📝️ Custom Components 과제의 컴포넌트들이 작동하는 로직을 의사코드로 작성하기

양이 많은 관계로 CSS 부분은 제외하고 기능 부분만 작성한다.
(제발 velog에서 접기 기능 좀 구현해줬음 좋겠다. detail 태그가 안먹힌다!!)

1. Modal
2. Toggle
3. Tab
4. Tag
5. Autocomplete
6. ClickToEdit


1. Modal


modal 작동 이미지 modal 작동 이미지

의사 코드

  1. 화면에 오버레이로 띄울 모달 창이 열려있는 상태, 닫혀있는 상태를 관리할 useState 함수를 만들어준다.
    ModalBtn 을 누르기 전에는 닫혀 있는 상태가 기본값이므로, isOpen의 초기값을 false 로 준다.
  2. openModalHandler 를 이용하여 isOpen 상태를 변경해준다.
    (Modal이 open 되어있으면 닫히게/닫혀있으면 열리게 구현하기 -> Boolean 값이니까 !isOpen 조건으로 true <-> false 를 바꿔주면 된다.)
    2-1. ModalBtn 에 onClick 이벤트가 일어나면 실행되도록 이벤트를 설정해준다.
  3. ModalBtn 에 Modal이 open 되었을 경우 'Opened!', 닫혀있는 경우 'Open Modal' 텍스트를 띄울 수 있도록 조건식을 사용하여 ModalBtn 내부 텍스트를 변경해준다.
  4. Modal이 open 되었을 경우 모달창과 배경이 뜰 수 있도록 조건식을 사용하여 ModalBackdrop 과 ModalView 를 렌더링해준다.
  5. Modal 창(ModalView) 외의 다른 부분, 즉 ModalBackdrop 영역을 클릭했을 때 모달창이 닫힐 수 있도록 onClick 이벤트에 openModalHandler 함수를 연결해준다.
  6. ModalBackdrop 영역이 아닌 모달 창을 클릭해도 모달 창이 닫히는 결과가 나온다. 이벤트 버블링이 적용되었기 때문! 이벤트 버블링 이란 자식요소에서 이벤트가 발생했을때, 부모 요소에서도 같은 이벤트가 발생한 것처럼 동작하는 것이다. 이것을 막기 위해서 event.stopPropagation() 함수를 사용해준다.
  7. close 버튼을 눌렀을 때 모달 창을 닫기 위해 onClick 이벤트에 openModalHandler 함수를 연결해준다.
  8. CSS 로 ModalBackdrop 영역을 전체 화면을 덮도록(position:fixed 로 설정한 뒤 top, bottom, left, right 를 0으로 주면 화면의 끝까지 늘어난다!) 설정해주고 다른 부분도 만져주면 끝!

구현 코드

export const Modal = () => {
  // 1.
  const [isOpen, setIsOpen] = useState(false);
  // 2.
  const openModalHandler = () => {
    setIsOpen(!isOpen);
  };

    return (
    <>
      <ModalContainer>
      	// 2-1.
        <ModalBtn onClick={openModalHandler} > 
          // 3.
          {isOpen ? 'Opened!' : 'Open Modal'}
        </ModalBtn>

        // 4.
        {isOpen 
         //5.
         ?  <ModalBackdrop onClick={openModalHandler}>
        // 6.
          <ModalView onClick={(event) => event.stopPropagation()}>
            // 7.
            <CloseButton onClick={openModalHandler} className='close-btn'>X</CloseButton>
            <div className='desc'>모달창 open</div>
          </ModalView>
        </ModalBackdrop>
        : null}
      </ModalContainer>
    </>
  );
};

2. Toggle


toggle 작동 이미지 off toggle 작동 이미지 on

의사 코드

  1. toggle 의 on/off 상태를 관리할 useState 함수를 만들어준다.
  2. toggleHandler 로 isOn의 상태를 변경해준다.
    2-1. ToggleContainer 에 onClick 이벤트가 일어나면 실행되도록 이벤트를 설정해준다.
  3. Toggle Switch가 ON인 상태일 경우에만 toggle--checked 클래스를 div 엘리먼트 2개에 모두 추가해서 토글 스위치가 ON 일 경우의 CSS 설정을 해준다.(circle 버튼의 위치값을 가로로 이동하도록 변경해주고 transition 으로 애니메이션 효과를 준다.)
  4. 조건부 렌더링을 사용해서 Toggle Switch가 ON인 상태일 경우에 Desc(설명란) 컴포넌트 내부의 텍스트를 'Toggle Switch ON'으로, 그렇지 않은 경우 'Toggle Switch OFF'로 설정한다.

구현 코드

export const Toggle = () => {
  // 1.
  const [isOn, setisOn] = useState(false);
  // 2. 
  const toggleHandler = () => {
    setisOn(!isOn);
  }

  return (
    <>
    	// 2-1. 
      <ToggleContainer onClick={() => toggleHandler()} >
        // 3.
        <div className={isOn ? "toggle--checked toggle-container" : "toggle-container"}/>
        <div className={isOn ? "toggle--checked toggle-circle" : "toggle-circle"}/>
      </ToggleContainer>
      // 4. 
      <Desc>{isOn ? 'Toggle Switch ON' : 'Toggle Switch OFF'}</Desc>
    </>
  );
};

3. Tab


tab 이미지 tab1 tab 이미지 tab2

의사 코드

  1. 현재 어떤 Tab이 선택되어 있는지 확인하기 위한 currentTab 상태를 관리할 useState 함수를 만들어준다.
  2. 현재 선택된 Tab Menu 가 갱신되도록 현재 선택한 인덱스 값을 전달해주는 selectMenuHandler 함수를 만들어놓는다.
  3. map 을 이용해서 탭 목록을 구성할 <li> 태그를 만들어주면서 현재 tab의 index 가 currentTab 의 값과 같은지 확인한다.
    3-1. 같으면 조건식을 이용해서 className 에 focused 를 추가해 준다.
  4. <li> 에 onClick 이벤트가 일어나면 selectMenuHandler 함수가 실행되도록 이벤트를 설정해준다.
  5. 현재 선택된 탭의 내용(content)을 렌더링해준다.

구현 코드

export const Tab = () => {
  // 1.
  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) => {
    // 2.
    setCurrentTab(index)
  };

  return (
    <>
      <div className='tab-container'>
        <TabMenu>
          // 3. 
          {menuArr.map((el, index)=>{
    	  // 3-1.
            return <li className={index  === currentTab? "submenu focused" : "submenu"} 
    	  // 4.
             onClick={()=>selectMenuHandler(index)} key={index}>{el.name}</li>
          })}
        </TabMenu>
        <Desc>
          // 5.
          <p>{menuArr[currentTab].content}</p>
        </Desc>
      </div>
    </>
  );
};

4. Tag


tag 이미지

의사 코드

  1. 태그의 상태를 관리할 useState 함수를 만들어준다.
  2. filter 를 이용해서 태그 삭제 메소드를 만들어준다. 삭제할 index 의 tag 외의 다른 태그들만 새로운 배열로 필터링해서 setTags 상태변경함수를 이용하여 tags 의 상태를 변경해준다.
  3. addTags 함수를 통해 tag 배열에 새로운 태그를 추가하기(input 태그에서 onKeyUp 이벤트 발생 시 addTags 함수로 event.target.value 를 가져오기)
    3-1. event 의 key 속성이 "Enter"일 때 실행하기
    3-2. 이미 입력되어 있는 태그인지 검사하여 이미 있는 태그라면 추가하지 말기
    3-3. 아무것도 입력하지 않은 채 Enter 키 입력시 메소드 실행하지 말기
    3-4. 태그가 추가되면 input 창 비우기
  4. setTags 로 tags 배열에 태그를 추가할 때, push 메소드를 사용하면 tags 배열의 주소값이 바뀌지 않아서 React 가 상태가 바뀌지 않았다고 판단하여 리렌더링을 실행하지 않음.
    그래서 spread 연산자로 배열을 풀어주고 새로운 태그를 합친 새로운 배열로 만들어줌.
  5. map 메소드를 사용해서 tags 요소를 렌더링해준다.
  6. 클릭 시 removeTags 함수를 이용해 해당 요소를 삭제하는 버튼을 구현해준다.

구현 코드

export const Tag = () => {
  const initialTags = ['Cats', 'Dogs'];
  // 1.
  const [tags, setTags] = useState(initialTags);
  const removeTags = (indexToRemove) => {
    // 2.
    const filter = tags.filter((el,index) => index !== indexToRemove);
    setTags(filter);
  };

  const addTags = (event) => {
	//3. 
    const inputValue = event.target.value;
    // 3-1, 3-2, 3-3
    if(event.key === "Enter" && inputValue !== '' && !tags.includes(inputValue)){
      // 4. 
      setTags([...tags,inputValue]);
      // 3-4.
      event.target.value = '';
    }
  };

  return (
    <>
      <TagsInput>
        <ul id="tags">
    		// 5.
          {tags.map((tag, index) => (
            <li key={index} className="tag">
              <span className="tag-title">{tag}</span>
				// 6.
              <span className="tag-close-icon" onClick={ () => removeTags(index)}>
              x</span>
            </li>
          ))}
        </ul>
        <input
          className="tag-input"
          type="text"
          onKeyUp={(e) => {
			// 3-1.
              addTags(e) 
          }}
          placeholder="Press enter to add tags"
        />
      </TagsInput>
    </>
  );
};
profile
새싹 프론트엔드 개발자

0개의 댓글