※ 해당 포스트는 http://100dayscss.com/의 98번 글의 설명을 위해 작성자가 다시 재구성한 포스팅입니다.

※ 무단 스크랩은 허용하지 않습니다.

※ 





다양한 도형을 이용하여 뭔가 중심에서부터 폭발하는 것 같이 보이는 애니메이션을 꾸며볼까 합니다. 


바로 시작할까요? 준비물부터 챙겨보겠습니다.


- 삼각형, 사각형 및 다채로운 도형

- 애니메이션 활용 방법 : 애니메이션에 대해 모르시면 잠시 들렀다 오세요.

- position 활용 방법 : position에 대해 모르시면 잠시 들렀다 오세요.

- transform에 대한 이해 : transform에 대해 모르시면 잠시 들렀다 오세요.


먼저, 기본적인 레이아웃 구성에 삼각형을 그려보겠습니다.

See the Pen aWeYpV by Munkyu Yang (@moonformeli) on CodePen.


지금 현재로써는 밑바탕이 되어줄 #wrapper div와 나머지 .clip div들에 대한 레이아웃만 설정되어 있는 상태입니다.  이 사각형들을 전부 삼각형으로 바꾸어준 후에 position을 이용해 적절히 배치를 해보겠습니다. 우선, 삼각형, 오각형, 육각형 등 사각형이 아닌 다른 특수한 도형을 그릴 때는 clip-path라는 것을 이용해야 합니다. clip-path는 좌표 값을 찍어 그 점들을 모두 잇고, 점과 점 사이로 연결된 선의 안쪽 영역을 도형의 모양이라고 간주합니다. 즉, 삼각형을 그리려면 좌표 3개가 필요하고, 이 3개의 좌표는 자동으로 이어지며 그렇게 생긴 선들의 안쪽 영역(삼각형 내부)이 화면으로 보여지게 될 영역이라고 간주되는 것입니다.


아래의 사이트는 clip-path에 대해 가장 보기 쉽고 좋게 구현된 사이트입니다.

http://bennettfeely.com/clippy/


방법은 아~주 간단합니다. 그저, 복사 후 붙여넣기 입니다.


약간의 position을 주어 모양을 갖춰보겠습니다.


See the Pen RVXMYz by Munkyu Yang (@moonformeli) on CodePen.


방금 바로 위에서 설명한대로, 사이트에 접속해 원하는 도형을 선택 후에 나온 코드를 그대로 복사 후 붙여넣기 하였습니다. 코드에 표현된 %는, 예를 들어 100% 50%라면, 해당 좌표는 x축으로 100%만큼, y축으로 50%만큼 이동했다는 뜻입니다. %의 범위는 현재 작업중인 태그의 크기입니다. 즉 100px의 div로 작업을 한다면 100%면 100px, 50%면 50px이 되겠죠.


이제 우리는 어떻게 삼각형을 그리는지 알았습니다. 이제는 여러가지 다채로운 도형들을 넣어보겠습니다. 제 코드를 보고 연습하시게 될 경우에는 이런 저런 다른 도형들도 커스터마이징해서 넣어보세요.


See the Pen XRvEwq by Munkyu Yang (@moonformeli) on CodePen.


겉보기에는 다를 것 없어보이나요?  코드를 먼저 살펴보겠습니다.


.clip에 설정된 z-index를 봐주세요.  z-index는 같은 영역에 2개 이상의 요소들이 위치할 때, 어떤 것부터 먼저 보여줄지를 결정하는 속성입니다. z-index가 높을수록 우선순위가 높아집니다.


다음으로는,  새롭게 추가된 도형 클래스를 살펴보겠습니다. 먼저 예를 들어, .circle-1 클래스에는 .circle이, .close-1 클래스에는 .close 라는 식의 클래스가 모든 도형들마다 설정이 되어있습니다. 당장에는 필요없는 작업이지만, 이것은 만약의 상황에서, 같은 도형이 더 추가가 될 경우, 클래스 재사용을 위해 넣어둔 것입니다. 이렇게하면 나중에 삼각형을 10개를 그린다고 가정할 때 하나하나 일일히 속성을 부여해주지 않아도 되는 것이죠.


그리고 한 가지 더 궁금해하실 법 한 것은 바로 clip-path를 사용해 만든 도형의 border를 어떻게 적용하냐의 문제입니다. 이러한 것은 딱히 방법은 없습니다. 단지, 새롭게 같은 모양의 도형을 그 위에 하나 더 그리고, 크기를 약간 작게하면 뒤에 가려진 도형이 조금 노출이 되겠죠? 마치 테두리가 입혀진 것처럼요. 이러한 것은 현재 우리가 다루고 있는 예제에서는 코드의 양만 늘릴 뿐이라 생각되어 추가하지는 않았습니다. 관심있으신 분들은 따로 시도해보세요.

자세한 내용은 https://stackoverflow.com/questions/31854185/how-to-add-border-in-my-clip-path-polygon-css-style 에서 참고하실 수 있습니다.



위의 사진은 .clipz-index 속성을 갖지 않았을 때 나타나는 모습입니다. 왜 z-index를 설정해주어야 하는지 이제 이해하시나요?


자, 이제 얼마 남지 않았습니다. 드디어 기다리던 애니메이션을 넣어줄 시간이 왔습니다. 그 전에, 이 이야기를 먼저 다뤄보도록 하죠. 우리는 여기서 우주의 빅뱅처럼, 가운데에서 사방으로 흩뿌려지듯이 퍼졌다가 다시 모아지는 애니메이션을 다루고 싶습니다. 그런데, 퍼졌다가 돌아올 때의 약간의 시간차를 느끼게 해주고 싶어요. 무슨 말인가하면, 

위의 사진은 어떤 물체가 포물선 낙하운동을 하고 있을 때의 곡선입니다. 물체가 올라갈 때와 낙하할 때는 속도가 빨라졌다가 느려지거나 혹은 느려졌다가 빨라지는 운동을 하죠. 그러나 곡선의 최정점에서는 물체는 느린운동을 합니다. 마치 일순간 정지해 있는 것과 같은 착시를 불러일으키죠. 우리는 여기서 그러한 효과를 만들어보겠습니다.


animation의 animation-timing-function에는 animation의 진행속도를 설정할 수 있는데, 우리는 여기서 cubic-bezier라는 것에 집중을 해보겠습니다. cubic-bezier는 사용자가 임의의 운동 그래프를 커스터마이징할 수 있는 기능을 제공해주는데, 해당 링크로 들어가시면 직접 곡선을 그려볼 수 있는 화면이 나옵니다. 

https://dbaron.org/css/timing-function-graphs


animation은 이번에는 @keyframes를 이용해 구현하도록 하겠습니다. @keyframes는 설정하고자 하는 animation이 2개 이상이거나 단일 animation에서 여러가지 효과를 구간별로 다양하게 설정하고 싶을 때 유용하게 사용될 수 있습니다.


See the Pen zwgaqx by Munkyu Yang (@moonformeli) on CodePen.


이제 거의 다 왔습니다. cubic-bezier효과를 사용하니 정점에서 마치 거의 멈춘 것 처럼 느리게 움직이는 걸 보실 수 있을겁니다. 이처럼 cubic-bezier는 매우 유용하게, 또 흔하게 사용되는 효과이니 기억해두시면 좋겠네요.


이제 남은 작업은 단 하나입니다. 각 도형을 적절히 움직이게끔 위치를 설정해주는 일만 남았습니다. 여기서 한 가지 더 추가하자면, 생동감을 넣어주기 위해 도형에 rotateZ 속성을 넣어주겠습니다. roateX는 X축을 기준으로, rotateY는 Y축을 기준으로 이미지를 상하 혹은 좌우 반전을 시키지만 rotateZ는 시계/반시계 방향으로 이미지를 돌릴 때 사용하는 속성입니다.


See the Pen oWrVwQ by Munkyu Yang (@moonformeli) on CodePen.



이로써 이번 예제에 대한 설명은 모두 끝났습니다.


항상 생각하지만 저의 부족한 설명이 글을 여기까지 읽어주신 분들에게 얼마나 도움을 드렸을지 모르겠습니다. 도움이 되셨길 바라며, 궁금하신 점 있으시면 언제든지 댓글 달아주시면 답변 드리겠습니다.





※ 해당 포스트는 Dave Ceddia 님의 동의 하에 글을 번역한 것임을 알립니다.


※ 자연스러운 글의 흐름을 위해 작성자의 임의로 의역한 부분이 있음을 알립니다.







React 컴포넌트가 제대로 렌더링이 안되고 있습니까?


그 전에 잠깐! React 컴포넌트가 componentWillMount 에서 서버로부터 데이터를 받아오는 작업을 아래와 같이 하고 있다면, 과연 무엇이 렌더링이 될까요?



사진의 출처 - Jay Galvin



만약 '아무것도 일어나지 않는다' 혹은 'a console error'라고 생각하셨다면, 정답입니다.

만약 '데이터를 받아온다'고 생각했다면, 이 포스트를 읽으시는게 좋겠군요.


State는 초기화되어 있지 않다

우선 여기서 짚고 넘어가야할 두 가지 중요한 사실들이 있습니다:

1. 컴포넌트의 상태 값(e.g. this.state) 의 시작 값은 null이다.
2. 비동기적으로 데이터를 처리할 때, 컴포넌트는 적어도 한 번, 데이터가 불러지기 전에 렌더링 된다.

- 데이터가 constructor, componentWillMount , componentDidMount 혹은 그 어디에 있는지와 상관이 없이 말이다.


그렇습니다. constructorcomponentWillMount가 최초의 렌더링 그 이전에 실행이 된다고 할지라도, 비동기 호출은 컴포넌트가 비동기 이전에 렌더링이 되는 것을 막아주지는 못합니다. 그래서 여러분이 여전히 문제를 일으키고 있는 것이고요.


해결방안

사실 해결책은 간단합니다. 가장 쉬운 방법은 constructor 안에서 state를 그럴싸한 값으로 기본 설정해주는 것입니다.


위의 컴포넌트에 대한 예제는 아래와 같이 풀어볼 수 있습니다.


그리고 아래처럼 또한 빈 값을 render 안에서 설정해줄 수도 있습니다.



이 것은 이상적인 방법은 아닙니다. 만약 기본 설정 값(default value)을 부여할 수 있다면, 그렇게 하세요.


낙수효과(Trickle-Down effect)의 실패에 따른 부작용

"비어있는 상태값(state)"이 만약 제대로 설정이 되어 있지 않다면, 결국에 이 문제는 개발자에게 더 큰 후폭풍을 안겨주게 됩니다.

(※ 작성자에 의한 의역임을 알림(or를 오타로 판단해 of로 해석). 원문 : The lack of default or “empty state” data can bite you another way, too)

바로 자식 컴포넌트에게 정의되지 않은(undefined) 상태값이 전달될 때 말이죠.


위의 예제를 조금 더 확장해 봅시다. 가령 Quiz 컴포넌트안에 있는 자식 컴포넌트로 list를 넘겨준다고 한다면,



문제가 보이시나요? Quiz가 처음으로 렌더링이 될 때, this.state.itemsundefined 입니다. 무슨 말인가하면, ItemList 컴포넌트가 items 이라는 데이터를 undefined 상태로 넘겨받게되고, 결국에는 화면에서 Uncaught TypeError: Cannot read property 'map' of undefined 를 보게되는 것이란 말입니다.


만약 ItemList안에 propTypes에 대한 정의가 컴포넌트에 새겨져 있었다면 디버깅하기는 더 수월했겠군요.



이렇게 정의가 되어 있었다면 콘솔에 나오는 메시지는 다음과 같습니다.

"Warning: Failed prop type: Required prop items was not specified in ItemList."

(경고: prop type 오류: 필수요건인 itemsItemList에 정의되어 있지 않음.)


그러나 여전히 Uncaught TypeError: Cannot read property 'map' of undefined 의 에러는 남아있습니다. propType의 유효성을 검사하는 것은 컴포넌트의 렌더링에 관한 문제를 해결해주지는 않습니다. 다만 알려주기만 할 뿐이죠.


그러나 최소한 이러한 방법은 디버그를 조금 더 수월하게는 해줍니다.


기본 Props 설정(Default Props)

한 가지 더 쉬운 방법이 있습니다. props의 default값을 설정해주면 됩니다.


Default props는  항상 최선책은 아닙니다. 이 방법을 사용하기전에 더 나은 해결책이 없는지, 이 방법이 그저 임기응변(band-aid solution)에 지나지 않는지 항상 확인하세요.


Default 값들을 설정하는 것이 그저 값들이 정의되지도 않아서 발생하는 수 많은 에러들을 모두 예방해줄 수 있을 것이라 생각하시나요? 그 전에 값(data)들을 제대로 정의하는 것을 먼저 고려하십시오.


아니면 prop이 단순한 선택적인 것에 불과하다고 말할 수 있습니까? prop이 전달되지 않은 상태에서 컴포넌트가 렌더링이 되는 경우에 대해서는 문제가 없다고 생각하십니까? 그렇다면 기본 값 설정에 대한 문제 해결을 받아들일 준비가 되었습니다.


이 문제는 몇 가지 방법으로 해결할 수 있습니다.


defaultProps 이용하기

이 메소드는 여러분의 컴포넌트가 상태(state)를 갖고 있지 않은 함수인지, React.Component를 상속받는 클래스인지에 얽매이지 않습니다.



이 메소드는 컴포넌트가 클래시 형식일 때, 여러분의 컴파일러가 ES7의 static initializer 문법을 지원할때만 동작합니다. 



render 조작

이 방법은 아래에 있는 render 안에서, ES6의 destructuring syntax에 의해 다음과 같이 표현됩니다.



이 라인은 다음과 같은 의미입니다.

"items 키를 this.props에서 가져오고, 만약 undefined상태라면 빈 배열로 초기화한다"



인자 값(arguments) 조작

만약 컴포넌트가 함수형이라면, 아래와 같이 초기화를 해줄 수 있습니다.



요약

  • 컴포넌트 라이프 사이클이 실행되는 동안에 이루어지는 비동기 호출은 컴포넌트가 데이터가 로드되기 전에 렌더링이 된다는 것을 의미합니다. 그래서..

  • constructor 안에서 state를 초기화하거나 빈 값을 적절히 처리해야 합니다.

  • 디버깅을 더 수월히 하기 위해 ProTypes를 사용하십시오.

  • defaulProps를 적절히 활용하세요.

  • 구조 변경(※ 의역, 원문: Destructuring syntax: 구문 파괴)은 깔끔하면서 쉽게 기본 값들을 설정할 수 있습니다.



+ Recent posts