All Articles

wecode 8주차_1일 TIL_리액트에서 탭 이동 및 선택한 탭 색깔 칠하기

image.png

오늘 점심먹고서부터 시작된 나의 삽질은 저녁먹기 바로 직전에 끝이 났다ㅋㅋ 탭이동 하는 로직은 안 쓰는 사이트가 없기 때문에 꼭 알아야하는 로직이다! 삽질을 꽤나 오래하긴 했지만 일단 정리를 해야 까먹지 않을것 같아서 정리 시작!

첫 번째 도전…

image.png

일단 컴포넌트를 쪼개서 각 탭을 눌렀을 때마다 오른쪽 화면에 보이는 구성을 다르게 하려고 했다. 그래서 써본 것.. 먼저 render함수 전에 switching이라는 함수를 만들었다. 더 전엔 constructor 안에 this.state={rightbox:0} 이라고 선언해줬다.

//switching 함수
  switching = e => {
    if (e.target.key === 0) {
      this.setState({ rightbox: 0 });
    } else if (e.target.key === 1) {
      this.setState({ rightbox: 1 });
    } else {
      this.setState({ rightbox: 2 });
    }
  };

그러고 나서 적용했던 것이 <AdRight>라는 div 내부에 컴포넌트를 불러오는 조건문을 넣고, <AdSideLi>this.switching이라는 함수를 실행했다. 이렇게.

<ModalBackground>
        <ModalWrapper>
          <TitleWrapper>
            <TitleLetters>Adwards</TitleLetters>
          </TitleWrapper>
          <AdVideoWrapper>
            <AdLeft>
              <AdSideUL>
                <AdSideLI
                  onClick={this.switching}
                >
                  <Span>광고 영상 업로드</Span>
                </AdSideLI>
                <AdSideLI
                  onClick={this.switching}
                >
                  <Span>퀴즈 업로드</Span>
                </AdSideLI>
                <AdSideLI
                  onClick={this.switching}
                >
                  <Span>금액 설정</Span>
                </AdSideLI>
              </AdSideUL>
            </AdLeft>
            <AdRight>
               {this.state.rightbox === 0 ? (
                <AdVideoForm />
              ) : this.state.rightbox === 1 ? (
                <AdQuizForm />
              ) : (
                <AdMoney />
              )}
            </AdRight>
          </AdVideoWrapper>
          <CloseOK>
            <CloseLetter cancel>취소</CloseLetter>
            <CloseLetter>확인</CloseLetter>
          </CloseOK>
        </ModalWrapper>
      </ModalBackground>

결과는 대 실패! 여러가지 이유가 있지만 일단은 this.state.rightbox가 제대로 돌지 않아 2만 찍혔고… onClick에도 잘못된 함수를 넣었고, switching이라는 함수도 조건이 이상하다!

2차 시도

Switching = e => {
    this.setState({ rightbox: e.currentTarget.id });
}

일단 switching이라는 함수를 이런식으로 변형하고.. render 이후에 subView라는 배열을 선언해서 컴포넌트를 그 배열안에 넣고 인덱스 값으로 불러왔다. 이렇게..

// 이건 subView 배열
let subView = [<AdVideoForm />, <AdQuizForm />, <AdMoneyForm />];
// 이건 onClick 걸어준 태그
<AdSideLI id="0" onClick={this.Switching}>
<AdSideLI id="1" onClick={this.Switching}>
<AdSideLI id="2" onClick={this.Switching}>

그러고 나선 <AdRight>이라는 div 안에 다음과 같은 조건을 넣어주었다.

{subView[this.state.rightbox]}

이렇게 하면 탭 이동은 잘 되긴 한다!1 근데 나는 여전히 탭의 색깔을 바꿀수 없었고.. 제일 큰 문제는.. react 세상에선 id값을 잘 안준다는 점!!! id 자체가 고유한 값이라 리액트의 장점 중 하나인 재사용성이라는 성질에 맞지 않기 때문이다.

그래서 바꾼 코드는 다음과 같다.

class ModalForm extends Component {
  constructor() {
    super();
    this.state = {
      activeTab: "videoTab"
    };
  }

  switchMenu = activeTab => {
    this.setState({ activeTab: activeTab });
  };

  render() {
    let subView = [
      { videoTab: <AdVideoForm key="0" /> },
      { quizTab: <AdQuizForm key="1" /> },
      { priceTab: <AdMoneyForm key="2" /> }
    ];

    console.log(this.props.activeTab, "액티브");
    return (
      <ModalBackground>
        <ModalWrapper>
          <TitleWrapper>
            <TitleLetters>Adwards</TitleLetters>
          </TitleWrapper>
          <AdVideoWrapper>
            <AdLeft>
              <AdSideUL>
                <AdSideLI
                  active={this.state.activeTab === "videoTab"}
                  onClick={() => this.switchMenu("videoTab")}
                >
                  <Span>광고 영상 업로드</Span>
                </AdSideLI>
                <AdSideLI
                  active={this.state.activeTab === "quizTab"}
                  onClick={() => this.switchMenu("quizTab")}
                >
                  <Span>퀴즈 업로드</Span>
                </AdSideLI>
                <AdSideLI
                  active={this.state.activeTab === "priceTab"}
                  onClick={() => this.switchMenu("priceTab")}
                >
                  <Span>금액 설정</Span>
                </AdSideLI>
              </AdSideUL>
            </AdLeft>
            <AdRight>
              {subView.map((el, key) => {
                el.key = key;
                return el[this.state.activeTab];
              })}
            </AdRight>
          </AdVideoWrapper>
          <CloseOK>
            <CloseLetter cancel>취소</CloseLetter>
            <CloseLetter>확인</CloseLetter>
          </CloseOK>
        </ModalWrapper>
      </ModalBackground>
    );
  }
}

state값 변경

일단 state 안에 activeTab: "videoTab"이라고 디폴트값을 광고업로드 컴포넌트로 설정을 해주었고 switching 함수도 변형을 해주었다.

swtich 함수 변경

  switchMenu = activeTab => {
    this.setState({ activeTab: activeTab });
  };
  1. 이름을 동사+명사로 바꾸기(Switching -> switchMenu)
  2. state객체안의 key값인 activeTab의 value를 setState를 이용해 함수의 인자로 바꾸어주기

인자도, 키값도, value도 다 activeTab이라서 헷갈릴 수도 있다. 그럼 이름을 바꿔보자!

 switchMenu = icecreawm => {
    this.setState({ activeTab: icecream });
  };

이렇게 바꿔줘도 아주 잘 불러와진다.

image.png

오늘은 글이 너무 많은것 같으니 아이스크림짤 투척! 절대 내가 먹고싶어서 그런게 아니다. 정말이다!

여튼… 다시 이어서!!!!

컴포넌트를 불러오는 평범한 배열 subView를 객체를 가진 배열로 변형도 했다.

자식 컴포넌트 불러오는 배열 변경

 let subView = [
      { videoTab: <AdVideoForm key="0" /> },
      { quizTab: <AdQuizForm key="1" /> },
      { priceTab: <AdMoneyForm key="2" /> }
    ];

이 때 주의사항!

  • 배열 안의 객체의 value를 불러와야 하기 때문에 아래서 map을 돌려야 한다.
  • map을 돌려야 해서 jsx 내부에 고유의 key값을 설정해주어야 한다.

클릭이 되는 왼쪽 탭 안의 태그 조건 변경

            <AdLeft>
              <AdSideUL>
                <AdSideLI
                  active={this.state.activeTab === "videoTab"}
                  onClick={() => this.switchMenu("videoTab")}
                >
                  <Span>광고 영상 업로드</Span>
                </AdSideLI>
                <AdSideLI
                  active={this.state.activeTab === "quizTab"}
                  onClick={() => this.switchMenu("quizTab")}
                >
                  <Span>퀴즈 업로드</Span>
                </AdSideLI>
                <AdSideLI
                  active={this.state.activeTab === "priceTab"}
                  onClick={() => this.switchMenu("priceTab")}
                >
                  <Span>금액 설정</Span>
                </AdSideLI>
              </AdSideUL>
            </AdLeft>
  • css에서 background-color 변경을 위한 조건. 이건 아래에서 다시 살펴보자 AdSideLi태그에 active라는 props값을 주고, 그 props가 this.state.activeTab이 각각의 activeTab이
  • state 변경을 위한 조건 onClick 안에 함수선언을 해주었다. 호출 말고 선언!! 함수의 호출은 브라우저가 하는거기 때문에 우리가 미리 호출해버리면 안된다!

함수의 괄호 안에는 subView 함수에 내장되어있는 객체들의 key값을 넣어주었고, switchMenu라는 함수 자체가 parameter로 받는 값이 곧 activeTab이 되는 함수라서 state값이 각각 “videoTab”, “quizTab”, “priceTab” 으로 변경 되는것이다… 와우…넘나 신기해 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

소환 되는 자식컴포넌트가 들어갈 div안의 조건식 변경

            <AdRight>
              {subView.map((el, key) => {
                el.key = key;
                return el[this.state.activeTab];
              })}
            </AdRight>

subView는 객체가 아닌 배열! 객체를 품은 배열이다. 그래서 el값의 activeTab을 불러오도록 했고.. key를 넣어주지 않아도 되긴 하지만 개발자 도구에 빨간색으로 경고가 뜬다. 경고 받으면 무서우니까 넣어주자. 이 작업을 위해 컴포넌트 태그 안에 key를 넣어주었다!

CSS에서 props를 통해 탭 이동시 탭 배경색깔 바꾸기

const AdSideLI = styled.li`
  display: flex;
  padding-right: 24px;
  font-size: 15px;
  margin: 30px 0;
  background-color: ${props => (props.active ? `#E2E2E2` : null)};
`;

bgcolor를 바꿔줄건데.. props.active가 true일 경우 회색깔로 바꿔줄거다. 그렇다면 true와 false를 가르게 위한 조건은 뭐였을까! 바로 이거다.

active={this.state.activeTab === "videoTab"}
active={this.state.activeTab === "quizTab"}
active={this.state.activeTab === "priceTab"}

각각의 <AdSideLi> 태그 안의 값이다. 전체식은 아까 위에서 썼다~ 참고쓰~~ 클릭을 할때마다 state객체의 activeTab이 바뀌게 되는데 이렇게 설정해주면 클릭할때만 클릭한 탭의 activeTab이 true가 나오기 때문에 css 조건에서의 삼항연산자가 true가 나오게 되서 색깔이 바뀐다.

조건이 2개까진 괜찮았는데 3개가 되서 좀 헤맸는데 이제 좀 이해가 갔다!!!! 다음번 탭 이동 로직 구할땐 지금처럼 크나큰 삽질은 안할것 같다 ㅋㅋㅋㅋ

image.png

어쨌든 지금은 적용 잘 된다는점! css는 나중에 손볼거다… 기능 구현할게 넘나 많닼ㅋㅋㅋ 2차 프로젝트 화이팅하자 둘둘!!!

Reference

  • 예리멘토님 미니 세션 ♥