본문 바로가기

공부 정리

22.01.05: typescript, React Storybook 이용 과제 (Arrow Function, currentTarget)

반응형

문제 1. (FirstTemplate 에 작성합니다.)

간단한 버튼 3개를 구현해주세요. 버튼 문서는 오른쪽 링크를 참조합니다. (https://mui.com/material-ui/react-button/)
첫 번째 버튼의 속성은 small 사이즈이며 outlined, primary 입니다.
두 번째 버튼의 속성은 medium 사이즈이며 contained, secondary 입니다.
세 번째 버튼의 속성은 large 사이즈이며 text, error 입니다.
 
const FirstTemplate: Story<IButtonProps> = (args) => {
  return (
    <>
      <Button size="small" variant="outlined" color="primary">
        Primary
      </Button>
      <Button size="medium" variant="contained" color="secondary">
        Secondary
      </Button>
      <Button size="large" variant="text" color="error">
        Error
      </Button>
    </>
  );
};

 

문제 2. (SecondTemplate 에 작성합니다.)

InputText 에 값이 없을 때 비활성화, 값이 있을 때 활성화 되는 버튼을 만들어주세요.
주석 처리된 Input 을 이용하면 됩니다.
버튼은 현재 import 되어있는 Button 컴포넌트를 활용하면 됩니다.
Template 에 작성되는 코드는 컴포넌트라고 생각해주시고, 최적화를 고려해서 작성해주세요!
 
 
const SecondTemplate: Story<IButtonProps> = (args) => {
  const [text, setText] = useState<string | number>;
  const handleChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
    setText(e.target.value);
  }, []);
  return (
    <div>
      <Input value={text} onChange={handleChange}> />
      <Button disabled={!text}>Submit</Button>
    </div>
  );
};

 

 

 

문제 3. (ThirdTemplate 에 작성합니다.)

 
interface 에 버튼 세 개를 만들어주세요.
interface 의 <div> 에는 emotion/css 를 활용해 margin 을 부여해주세요.
className이 Thing 인 <div> 태그는 styled 를 활용해 Thing 이라는 styled-component 를 만들어주세요.
Thing 스타일은 다음과 같습니다. width: 60px, height: 60px, border-radius: 25px, background-color: blue
첫 번째 버튼을 클릭하면 Thing 의 스타일이 width:30px, height:30px, background-color: red으로 변경됩니다.
두 번째 버튼을 클릭하면 Thing 의 스타일이 width:90px, height:90px, background-color: green으로 변경됩니다.
세 번째 버튼을 클릭하면 Thing 의 스타일이 원래대로 돌아옵니다.

 

// 수정 전

const ThirdTemplate: Story<IButtonProps> = (args) => {
  const buttons = useMemo(() => {
    return [
      { number: 1, id: 'red'},
      { number: 2, id: 'green'},
      { number: 3, id: 'blue'},
    ];
  }, []);
  
  const [changeButtonStyle, setChangeButtonStyle] = useState<String>('blue');
  const onButtonStyleChange = useCallback((e) => {
    const { id } = e.target;
    setChangeButtonStyle(id);
  }, []);
  
  return (
    <div>
      <Thing theme={changeButtonStyle} />
        <div className="interface">
          {buttons.map((button)=>{
            return(
              <Button key={button.id} id={button.id} onClick={onButtonStyleChange}>
                {button.number}
              </Button>
            ); 
          })}
        </div>
    </div>
  );
}

 

// 코멘트 수정 후

const ThirdTemplate: Story<IButtonProps> = (args) => {
  // 아래 콜백 함수가 Arrow Function일 경우 블록 레벨에서 실행될 로직이 없으면 바로 리턴한다.
  // Arrow Function에 대해 알아보기.
  const buttons = useMemo(
    () => [
      { number: 1, id: 'red' },
      { number: 2, id: 'green' },
      { number: 3, id: 'blue' }
    ],
    [],
  );
  // typescript string 타입은 String (x) --> string (o)
  const [changeButtonStyle, setChangeButtonStyle] = useState<string>('blue')
  // event에도 가능하면 타입을 바인딩 해주자
  // target 이 아니라 currentTarget으로 접근해야 id를 받아올 수 있다. target과 currentTarget의 차이점 조사하기.
  const onButtonStyleChange = useCallback(({ currentTarget }) => {
    const { id } = currentTarget;
    setChangeButtonStyle(id);
  },[]);
  
  // 실 매개변수도 구조분해가 가능하다.
  // Arrow Function에서 내부 로직 없이 바로 return 할때 블록으로 감싸서 명시적으로 return하는 경우 가독성이 떨어진다.
 return (
    <div>
      <Thing changeButtonStyle={changeButtonStyle} />
      <div className="interface">
        {buttons.map(({ id, number }) => (
            <Button key={id} id={id} onClick={onButtonStyleChange}>
              {number}
            </Button>
          ))}
      </div>
    </div>
  );
}

 

 

 

// 수정 전 styled component 코드

import styled from "@emotion/styled";

export const Thing = styled.div<{theme: String}>`
  width:  ${({ theme })=> theme ==="blue"? "60px": theme === "red"? "30px": "90px"};
  height: ${({ theme })=> theme ==="blue"? "60px": theme === "red"? "30px": "90px"};
  border-radius: 25px;
  background-color: ${({ theme })=> theme ==="blue"? "blue": theme === "red"? "red": "green"};
`
// 코멘트 수정 후

import styled from '@emotion/styled';

// props로 받으려고 제네릭으로 type을 주기 --> styled.div<{ state명: type명 }>  
export const Thing = styled.div<{ changeButtonStyle: string }>`
  width: ${({ changeButtonStyle }) =>
    changeButtonStyle === 'blue' ? '60px' : changeButtonStyle === 'red' ? '30px' : '90px'};
  height: ${({ changeButtonStyle }) =>
    changeButtonStyle === 'blue' ? '60px' : changeButtonStyle === 'red' ? '90px' : '90px'};
  border-radius: 25px;
  background-color: ${({ changeButtonStyle }) =>
    changeButtonStyle === changeButtonStyle};
`;

 

 

 

# Arrow Function

 

전통적인 함수표현의 간단한 대안책이지만 모든 상황에 사용할 순 없다. 

 

- this나 super에 대한 바인딩이 없으며 methods로 사용 안됨
- new.target 키워드가 없다
- 스코프 지정할 때 사용하는 call, apply, bind methods 이용 불가
- 생성자(Constructor)로 사용 불가
- yield를 화살표 함수 내부에서 사용 불가

 

구문

 

기본 구문

 

(param1, param2, ..., paramN) => { statements }
(param1, param2, ..., paramN) => expression
// 다음과 같다: => { return expression; }

// 매개변수가 하나면 괄호는 선택사항이다:
(singleParam) => { statements }
singleParam => { statements }

// 매개변수가 없는 함수는 괄호가 필요하다:
() => { statements }

 

고급 구문

 

// 객체 리터럴 표현 반환 위해 함수 본문(body)을 괄호에 넣는다:
params => ({foo: bar})

// 나머지 매개변수, 기본 매개변수 지원
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, ..., paramN = defaultValueN) => { statements }

// 매개변수 목록 내 구조분해할당도 지원됨
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); //6

 

 

짧게 함수 표현하는 방법

 

var elements = [
 'Hydrogen',
 'Helium',
 'Lithium',
 'Beryllium'
];

// 배열을 반환하는 map함수
elements.map(function(element) {
  return element.length;
});

// 위 함수를 아래와 같이 쓸 수 있다
elements.map((element) => {
  return element.length;
});

// 파라미터 하나 --> 괄호생략
elements.map(element => {
  return element.length;
});

// 화살표 함수에 문장이 유일하면 return, {} 생략
elements.map(element=> element.legnth);

// 이런 경우 length 속성만 필요함 --> 구조분해 할 수 있다. (destructing 매개변수 사용)
elements.map(({ length: lengthFooBArX }) => lengthFooBArX); 

// destructuring 파라미터 할당도 가능
elements.map(({ length }) => length);

 

참고: MDN Arrow fucntion

 

#  currentTarget

 

currentTarget는 읽기전용 속성이다. Event가 DOM을 통과할 때 이벤트의 현재 대상을 식별한다. 항상 이벤트 핸들러가 첨부된 요소 (이벤트가 걸려져있는 위치)를 참조하고 이벤트가 발생한 요소, 그 자식 요소를 식별한다. event.target은 실제 이벤트가 발생하는 위치, 내가 클릭한 요소를 반환한다. event.currentTarget과 event.target이 같을 수도 있지만 이벤트 위임을 통한 이벤트에서는 두 개가 다른 값을 가질 수 있다.

 

참고: 이벤트 버블링, 위임 target과 currentTarget차이, MDN: Event.currentTarget

 

 

# 회고

 

일단 작동하는 코드를 구현한 뒤에 코드를 고쳐나가는 방식으로 과제를 수행했다. Prettier가 설치는 되어있었지만 설정을 제대로 안해주었는데, 저장하면서 설정이 안먹히는것 같다 생각했는데 바로 여쭤 봤어야 했는데, 그냥 넘어갔던 점이 아쉽다. 다음엔 의문이 들때 바로 질문을 해야겠음. type지정을 하면서 코드를 작성 해 보는것이 처음이었는데 기존에 있는 코드들을 참고하면서 적용해 나가니 혼자 공부할 때 막막했던 때 보다 훨씬 수월했다. useMemo, useCallback을 추후 컴포넌트 최적화를 고려하여 사용하는 연습을 해 보았는데, 이 것을 어떻게 하면 최적화가 되었는지 확인할 수 있는지 알아봐야겠다. 참고 자료를 주셔서 해당 자료들을 바탕으로 좀 더 공부해야 봐야겠음

 

 

반응형