May 05, 2020
스크롤바 없애기, 스크롤 이벤트시 쓰토를 적용, 웹팩 빌드 시 dist폴더에서 디렉토리 적용, 모바일 기기로 접속 시 스크롤 튕김 현상, 스크롤탑 smooth가 안먹던 현상, in 문법, 공통로직 함수 처리, ptr, 로딩 컴포넌트 처리 시 마운트 두번 되는 에러, 트랜스폼과 fixed, last child처리, 이미지 너비 높이 같은 값, ts-ignore, ripple 이벤트, 이미지 스프라이트 제너레이터, React.memo의 얕은비교, css active, inline-flex, z-index 음수, history.location.state 활용, 객체 활용 타입 뱉기, mustache와 replace,
보통 웹에서 특정 설정을 해주지 않으면 내용물이 뷰포트 크기를 넘을떄 스크롤이 생긴다 세로로 넘으면 세로스크롤, 가로로 넘기면 가로스크롤이 생긴다. 때에따라서 이 스크롤바를 보여주고싶지 않을 떄가 있다.
몇가지 css를 적용해주면 스크롤바를 숨길 수 있다.
.box {
-ms-overflow-style: none; /* IE 와 Edge */
scrollbar-width: none; /* firefox */
}
.box::-webkit-scrollbar {
display: none; /* chrome, safari, opera */
}
브라우저별 셋팅이 조금씩 다르니 참고해야한다.
스크롤이벤트를 적용하면 사용자가 스크롤을 할때마다 감지되고 실행이 된다. 단순 콘솔로그만 찍어도 콘솔이 어마어마하게 많이 실행되는것을 알 수 있다. 스크롤 감지 자체가 큰 부담이 아니라고는 하지만 나름 줄여줄 수 있으면 깔끔하게 적용해보려고 하였다.
보통 throttle과 debounce를 이용하여 시간이 지남에 따라 함수를 몇번 실행할지 제어하는데 두개는 차이를 가지고있다.
디바운스는 그룹화하여 특정시간이 지난 후 하나의 이벤트만 발생하도록 하는 것 즉, 순차적 호출을 하나의 그룹으로 그룹화 한다. 연이어 호출되는 함수중 가장 마지막이나 가장 처음만 호출하도록 하는것.
쓰로틀은 이벤트를 일정한 주기마다 발생하도록 하는것 쓰로틀에 설정시간으로 1s를 주면 해당 이벤트는 1s동안은 한번만 실행된다.
쓰로틀을 적용해보기로하고 쓰로틀 함수를 정의해줬다
export default function throttle(fn, delay) {
let timer;
return function () {
if (!timer) {
timer = setTimeout (function () {
timer = null;
fn.apply(this, arguments);
},delay)
}
}
쓰로틀 이라는 함수에서 인자로 함수와 딜레이시간을 받는다. 그리고 타이머 변수를 하나 선언하고 쓰로틀 함수는 함수를 리턴하는데 그 함수는 타이머를 !timer 조건이 맞을 때 타이머를 setTimeout으로 함수를 넣어주고 그 함수 내부에서 timer = null이며 쓰로틀함수에서 인자로 받은 함수를 apply로 호출하고 셋타임아웃의 딜레이시간은 쓰로틀 함수에서 인자로 받은 시간이다. apply호출 같은경우 this를 공부할때 this를 어떻게 적용시킬지 호출단계에서 정해주는 느낌으로 받아들였는데 완전히 이해하지 않았다. 이렇게 쓰로틀 함수를 뺴놓고 사용할곳에서 import 해주고 사용한다
import throttle from '../throttle'
const scrollEvent = ....
window.addEventListener('scroll', throttle(scrollEvent, 1000))
// 스크롤 이벤트를 scrollEvent라는 함수를 걸어주고 그 함수는 1초마다 한번 실행
이렇게 하면 콘솔을 찍어도 전처럼 마구마구 찍히지 않는것을 확인할 수 있다.
웹팩 빌드를 할 때 dist폴더에 js파일과 css파일을 빌드하는데 js파일은 js디렉토리에 들어간다음 그안에서 빌드가 되었는데 css파일은 바로 dist폴더에서 빌드가 되었다.
- dist
-- a.css
-- b.css
-- js
--- a.js
--- b. js
기존의 세팅
{
loader: MiniCssExtractPlugin.loader,
options: {
publickPath: '/app/dist/css/'
}
... 나머지 css로더들
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
})
]
}
일단 셋팅에서 엔트리포인트가 한개가 아닌 두개여서 헷갈리는 부분이 많았고 아웃풋 셋팅에서 js파일들은 잘 js디렉토리를 바라보고 있길래 잘 들어갈줄알았지만 그러지 않았다. 그러다가 아웃풋에서 js 파일들을 어떻게 뱉는지 보았더니
output: {
filename: 'js/[name].bundle.js'
...
}
파일네임 앞에 js/ 가 있고 그리고 js디렉토리 안에 빌드가 되었다 혹시나 MiniCssExtractPlugin에서도 적용을 시키면 잘될까 확인을 해보았다.
세팅 후
{
loader: MiniCssExtractPlugin.loader,
options: {
publickPath: '/app/dist/css/'
}
... 나머지 css로더들
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].css'
})
]
그러니 이제 css파일들이 dist/css/a.css 이렇게 css디렉토리에 들어간것을 확인할 수 있었다,
모바일뷰를 작업할떄애는 보통 크롬에서 개발자도구를 켜고 작업을 한다. 그래서 아무런 문제가 없음을 확인하며 작업을 진행했었는데 실제 모바일 디바이스로 체크를 해보니 스크롤할때마다 중간중간에 잠긴것처럼 튕기고 스크롤이 안될때가 있었다. 그래서 처음에는 스크롤이벤트에 걸려있는 내용이 문젠줄 알았었는데 이벤트 내용을 살펴보아도 원인을 찾기 어려웠다. 그러던중 맥과 아이폰을 연결하고 모바일사파리 화면에서 보고있을떄 맥사파리에서 개발자도구로 요소검사를 할 수 있다는 것을 알게되어서 그렇게 체크를 해보았다. 그래서 이 요소 저 요소 만지고있었는데 최상단 div에
.main {
overflow-x: hidden;
}
이 걸려있던것을 지웠더니 정상적으로 작동되는것을 확인하였다. 사파리 연동 요소검사를 잘 활용해야겠다.
버튼 클릭시 스크롤을 최상단으로 올려주는 이벤트가 있었는데 자바스크립트 scrollTo()함수를 사용하여 옵션으로 smooth를 주고 서서히 올라가게 기능을 짰다. 이 역시 크롬에서 개발자도구로 확인할떄 아무 문제없이 잘 되었었는데, ios기기에서 버튼을 클릭했을 때, smooth없이 그냥 다이렉트로 한번에 화면전환이 되었다.
안드로이드기기에서 체크해보니 또 안드로이드에서는 잘 작동하였다. 어찌 ios에서도 적용할지 고민해보다가 react-scroll 라이브러리를 써서 윈도우 이벤트가아닌 라이브러리로 이벤트를 구현해보았고, 라이브러리의 애니메이션을 활용하였다.
import { animationScroll } from 'react-scroll'
const scrollTop = () => {
animation.scrollToTop()
}
그랬더니 적용 후 아이폰에서도 smooth 애니메이션이 잘 적용되었다.
이번에 새로 알게된 자바스크립트의 신기한 문법중 하나가 in 문법이다. 배열안에 요소가 존재하는지 boolean값으로 반환하는 것인데 다음과 같다
item in arr
// 아이템이 arr에 있다면 true 없다면 false
적용 한다면 다음과 같다
const arr = [1, 2, 3, 4, 5]
console.log(1 in arr) // true
console.log(6 in arr) // false
유용하게 사용할 수 있는 것 같아서 기억해두고 필요 시 사용해야겠다.
로딩 처리 관련해서 ptr과 연동하면서 공통 로직이 생겼는데, 페이지가 첫 마운트시 api요청을 하게되면 로딩상태를 true로 바꾸고, api요청이 끝나면 false로 바꾸어 첫마운트시 로딩 컴포넌트를 렌더링하고 그 후 타 컴포넌트를 렌더링 했다. 그리고 ptr기능을 적용하며 ptr시 api요청을 해야하는데 그 떈 로딩상태를 핸들링 할 필요가 없었는데 로딩상태만 다를 뿐 요청 로직은 같은데 처음엔 함수 2개를 작성했다.
useEffect(() => {
const func = async () => {
setLoading(true)
try {
...
} catch(e) {
...
}
setLoading(false)
}
},[])
.....
onRefresh = async () => {
try {
...
} catch(e) {
...
}
}
따로 빼서 정의를 하려 했는데 처음에는 같은 로직을 다른 상황에 어떻게 적용할지 난해했는데 조금 고민을해보니 자주 사용하던 방법이고, 간단한 문제였다 함수에 매개변수를 넘겨주어 refresh함수인지 마운트 함수인지 구분을 줬다.
const setList = async (loading) => {
if (loading) {
setLoading(true)
}
try {
...
} catch(e) {
...
}
if (loading) {
setLoading(false)
}
}
...
useEffect(() => {
setList(true)
})
...
const onRefresh = () => {
setList(false)
}
더 효율적인 방법은 차차 고민해봐야겠다.
보통 어플리케이션의 최상단에서 위로 쭉 드래그를 하면 새로고침이 되면서 데이터를 새로 불러오는 기능들이 있다. 예를들어 유튜브나 인스타그램을보면 최상단에서 위로 드래그 시 피드들이 새로 업데이트가 되고 내용이 바뀐다. 처음에는 단순히 스크롤포지션이 0이하로 떨어질때 이벤트를 걸어주면 된다고 생각했는데 아무 기능 없을떄 위로 스크롤이 안되었고 난해했다. 그래서 몇가지 라이브러리를 알아보던 중 react-simple-pull-to-refresh라는 라이브러리가 있어서 적용을 해보았다.
import PullToRefresh from 'react-simple-pull-to-refresh'
const app = () => {
...
return (
<PullToRefresh
onRefresh={onRefresh}
refreshingContent={jsx element}
maxPullDownDistance={number}
>
{children}
</PullToRefresh>
)
}
PullToRefresh컴포넌트 아래 칠드런으로 요소들이 들어가면 최상단에서 그 요소들이 드래깅 되었을때 특정 함수를 실행 시킬 수 있으며 그때 UI를 처리할 수 있다.
onRefresh속성 같은 경우에는 드래깅 시 처리되는 함수이다. refreshingContent는 드래깅시 보여줄 jsx요소이다.
maxPullDistance는 얼만큼 드래깅이 될지 상한치를 정해주는 속성이다.
더 다양한 속성들은
https://www.npmjs.com/package/react-simple-pull-to-refresh
위에서 정리한 로딩 관련한 문제였는데 메인 컴포넌트 밑 자식 컴포넌트에서 상태값 관리를 하는데 갑자기 언마운트 된 요소에서 상태값을 변경하려고 한다는 에러를 뱉어서 확인해보았다. 그랬더니 자식 컴포넌트에서 마운트 시 콘솔을 찍어보니 2번이 찍혔다
자식 마운트
부모 마운트
자식 마운트
부모의 구조는 다음과 같았다.
const parent = () => {
const [loading, setLoading] = useState(false)
useEffect(() => {
setLoadnig(true)
... api 요청
setLoading(false)
})
return loading ? (로딩요소) : (자식 컴포넌트)
}
처음에 원인을 찾지 못해서 답답했다. 그냥 조건부렌더링을 지우면 1번만 마운트되고 삼항연산자를 넣으면 2번을 했는데 생각해보니 굉장히 단순한 문제였다 첫 로딩값이 false이기에 처음 마운트 후 호출되는 유즈이펙트 전에 이미 로딩 상태값이 false인 상태로 자식이 마운트가 된다. 그리고 유즈이펙트에서 상태값 변경 후 언마운트 되었다가 다시 마운트가 되기에 총 2번이 되었던것. 일단 해결책은 첫 로딩값이 true이면 한번만 마운트된다. 로딩 자체를 false로 관리하고 껐다켰다 하려면 조건을 하나 더 추가해주었다.
const parent = () => {
const [loading, setLoading] = useState(false)
cpnst [list, setList] = useState(null)
useEffect(() => {
setLoadnig(true)
..api요청
setList(list)
setLoading(false)
})
if (loading) return 로딩요소
if (!list) return null
return 자식 요소들
}
위와같이 조건을 하나 더 걸어주고 해결할 수 있다.
이번에 ptr을 처리하면서 알게된 사실이다. 적용했던 ptr라이브러리가 자식 요소들이 transform으로 드래깅 시 위치가 조정되는 원리였다. 그래서 position:fixed 인 요소가 있었는데 fix가 되지 않았다. 알아보니 트랜스폼과 fixed가 함꼐사용되면 픽스가 되지않는다고 한다. 그래서 처음에는 당황했지만 ptr요소에서 position:fixed 속성을 가진 요소를 제거하고 밖으로 빼냈다.
last child 처리관련 새로 알게된 사실. 한 컴포넌트에 이미지 요소들이 있을때 다 공통적으로 마진을 주는데 마지막 요소에 넣지않고 싶을때가 있다. 그래서 처음에는 자바스크립트와 연동해서 map함수로 요소들을 배치하는데 index값이 마지막이거나 요소가 마지막요소일떄 다른 클래스값을 부여하는 방법을 했다. 그런데 생각해보니 그때마다 이 방법을 적용하면 비효율적이라 생각했고 분명 css에서 처리할 방법이 있다고 생각했다.
li:not(:last-child) {
margin: 10px;
}
이렇게 not선택자에last-child를 넣어주면 li 요소중 마지막 차일드 요소를 제외하고 마진이 10애 들어가게 된다. 꼭 last-child가 아니라 first-child도 가능하다 이것을 알게되고 기본이 굉장히 부족하다고 느꼈다 css에 분명히 소흘했는데 앞으로 컴포넌트 작성할때 이러한 방법들을 더 알아보며 기본기를 탄탄히 쌓아야겠다.
레이아웃 작업을 하던 중 화면 너비에따라 이미지 요소들의 크기가 정해지고 높이도 그 너비에 맞게 같은 값을 주고싶었는데 그게 잘 안되었다. 정사각형 카드를 만들기 위해서 이것저것 시도를 해보았지만 어려움이 있었다. 그러다가 찾게된 방법이다.
.list {
width: calc(100% - px);
}
.box {
position: relative;
}
.box:after {
content: '';
display: inline-block;
vertical-align: top;
width: 100%;
height: 0;
padding-top: 100%;
}
.card {
position: absolute;
top: 0;
height: 100%;
width: 100%;
}
각각의 요소들에 list클래스에서 정의한 너비가 들어가고 높이도 같은값을 가지게 하기 위함이었는데 저렇게 선택자 after속성을 주고 다음과 같은 내용을 정의하니 너비와 높이가 같은값이 맞춰졌다.
<li class="list">
<div class="box">
<img src="" class="card" />
</div>
</li>
html구조는 위와 같다.
ts-ignore 관련해서 가끔 프로젝트 작업을 하다보면 eslint-ignore를 적용할 때가 있었는데 ts에서 ts-ignore도 적용할 일이 있었다
data.map(el => <div data={el.data} />)
이런식으로 태그에 속성으로 데이터를 넣어줄일이 있었는데 자꾸 ts에서 없는 속성값을 할당할 수 없다고 에러를 뱉었다 그러다가 eslint처럼 ts도 이그노어를 적용할 수 있겠다 싶어서 찾아보게 되었다.
{/*
// @ts-ignore */}
이렇게 무시해야할 코드 위에 위와같은 코드를 작성하게 되면 에러를 뱉지 않는다 들여쓰기는 맞춰서 작성해야한다. 한줄로 작성하게되면 적용이 되지 않는다. 따라서 위와같이 ts-ignore를 적용할 수 있다.
material-ui나 여타 스타일 프레임워크를 보면 클릭할때 물결이 나오면서 애니메이션이 적용되는 것들이 있다. 알아보니 이런 애니메이션을 ripple이라고 하더라. 처음에는 어떤식으로 작동하는지 알아보았다. ripple의 원리는 클릭이 발생하면 해당 클릭한부분을 rect()로 감지해서 알고 요소 하나를 생성해서 absolute로 포지션속성을 잡고 감지한 지점으로 top과 left값을 준다 그리고 퍼져나가게끔 애니메이션을 적용한뒤 overflow hidden으로 흘러넘치는것을 잡는다.
Array.from(document.querySelectorAll('.ripple')).forEach(a => {
a.addEventListener('click', function(e) {
const ripple = document.createElement('div'),
rect = a.getBoundingClientRect()
;(ripple.className = 'animate'),
(ripple.style.left = `${e.x - rect.left}px`),
(ripple.style.top = `${e.y - rect.top}px`),
(ripple.style.background = `#${
a.dataset.color !== undefined ? a.dataset.color : 'red'
}`),
ripple.style.setProperty('--material-scale', a.offsetWidth),
a.append(ripple),
setTimeout(function() {
ripple.parentNode.removeChild(ripple)
}, 500)
})
})
이런식으로 적용을 해주더라. 위와같은 애니메이션을 편하게 적용할 수 있게 react-ripples라는 라이브러리가 있다.
npm install react-ripples
적용예제
import Ripples from 'react-ripples'
...
const rippleExample = () => {
...
return (
<Ripples during={1000} color='red'>
{children}
<Ripples/>
)
}
위처럼 props로 during값과 color값을 전달할 수 있는데 during은 물결이 퍼지는 시간이고 color는 색상이다. 위처럼 편하게 적용할 수 있다. https://www.npmjs.com/package/react-ripples
이미지 작업중 스프라이트를 적용하려고 알아보게되었다. 처음에는 이미지스프라이트 이미지들이 디자이너분들이 작업해서 하나의 이미지로 넘겨주는줄 알았는데 편하게 내가 만들 수 있었다.
https://spritegen.website-performance.org/
위의 사이트에서 이미지들을 설정해서 넣어주면 합쳐진 하나의 이미지로 만들어주는데, 뿐만 아니라 사진별 마진이 얼맞지 각각의 포지션이 어떻게 되는지 하나하나 알려주고 위치 조정도 할 수 있어 편하게 사용할 수 있다.
이미지 스프라이트를 하게되면 불러오는 이미지자체가 여러개가 아니라 한개이기때문에 더 효율적인 이미지 작업을 할 수 있다고 생각하는데 앞으로 유용하게 사용할 수 있을것같다.
React.memo 관련해서 한번 내용을 정리한적이 있는데, memo는 함수형 컴포넌트에서 렌더링을 최적화하는 목적으로 사용하는데 리액트에서 컴포넌트가 리렌더링 되는 이유는 4가지가 있다.
인데, class형 컴포넌트 에서는 purecomponent 함수형컴포넌트에서는 memo를 적용해주면 받은 props가 바뀔때만 컴포넌트가 재랜더링 되며 그 props비교는 성능향상에 목적을 두고 얕은비교를 한다. 리액트에서 불변성을 지켜야하는 중요한 이유이기도 하다. 근데 메모가 적용이 되지 않는 이슈가 발생하였다.
import React, { useState } from 'react'
...
const parent = () => {
const [state, setState] = useState([])
...
return (
<Child value={state.slice(0,2)} />
)
}
위와같이 props를 부모의 상태값에서 slice로 잘라서 내려줬었다. 처음에는 원인을 찾느라 고생을 했는데, slice를 하지않고 내려보니 리렌더링이 되지않아서 원인이 slice라는것을 찾았다. 리액트 공식문서에서 memo관련해서
function MyComponent(props) {
/* props를 사용하여 렌더링 */
}
function areEqual(prevProps, nextProps) {
/* newxprops와 prevProps가 같다면 true를 반환하고 아니면 false를 반환 */
}
export default React.memo(MyComponent, areEqual)
위와 같은 방법으로 memo함수에 두번째 인자로 areEqual함수를 전달해서 그 함수가 받는 이전 프랍스와 현재 프랍스를 비교했었을때도 false를 반환했었다. 자식에서 받은 props를 콘솔로 확인했을때는 항상 같은 값이었는데 아마 지금 조심스럽게 추측해보면 부모 컴포넌트가 리렌더링될떄마다 slice를 해서 props를 내려주는데 겉모양은 같지만 참조형데이터의 특성상 참조값이 리렌더링될때마다 다르게 전달되서 그런것 같긴하다. 정확히는 모르겠다. 더 알아볼 필요가 있을것같다.
프로젝트를 진행하면서 개발자도구를 보면 가끔 active 선택자가 있었는데 정확히 무슨역할을 하는지 몰랐다. 이번에 알아보게 되었는데 active란 해당 요소가 클릭이 되었을때 적용되는 속성이다. hover의 경우에는 마우스를 올릴 때 적용된다면 active는 클릭 시 떼지 않아도 적용이 된다.
div:active {
background-color: red;
}
위와같이 작성을 하면 div가 클릭이 되었을 때 배경색상이 red로 바뀐다.
flex레이아웃을 한참 활용하고 있는데 문제가 있었다. 모바일 기기로 접속 시 드래그 슬라이드 라이브러리를 적용했던 부분이 있는데, 수평슬라이더 였지만, 드래그하고 위아래로 흔들면 흔들렸다. 가만히 있어야할 부분이..
웃긴건 텍스트와 같이있는 슬라이더는 문제가 없었는데 텍스트가 없이 사진만 있는 슬라이더만 그랬다. 이유는 .. 모르겠다. 그래서 모바일 기기로 접속하고 사파리에서 요소검사기를 켜서 이것저것 만져보는데 애먹었다 원인을 찾을 수가 없었다.
그러다가 얼마전에 봤던 inline-flex가 생각이 났다. 드래그 슬라이더는 부모요소에 flex를 적용해서 자식을 정렬하는데, 한번 안될것 같지만 inline-flex나 적용해보자 했는데 버그가 잡혔다. 그 후 인라인 요소이기 떄문에 넓이가 달라서 넓이값을 100%로 맞춰주었다. 잡히고 나서도 원인은 모르겠다.
flex와 inline-flex의 차이는 block과 inline의 차이처럼 블락요소로 설정하는지 인라인요소로 설정하는지의 차이인데, 다음에 더 자세히 알아보아야겠다.
텍스트에 백그라운드 이미지 작업할 일이 있었는데, 텍스트 뒤에 이미지가 백그라운드 느낌으로 있는것이였다.
<div>
<p>안녕하세요</p>
<img src="img" />
</div>
위와같은 구조로 작업을 하고, 부모에 포지션속성을 준 다음 이미지에 absolute를 줘서 덮어 씌웠다. 그랬더니 텍스트보다 이미지가 위에 뜨게되었다 뒤로갔어야했는데, 그래서 텍스트를 띄우려고 z-index값을 넣어주었는데 그래도 이미지가 떠있었다. 생각하다가 한번 img에 -값을 주었더니 이미지가 뒤로 들어갔다. 원래 알던 원리라면 text에 1보다 큰 값만 주어도 텍스트가 더 위로 떠야하는데 그때는 적용이 안되고 이미지에 음수의 z-index를 주었을 때 뒤로 밀리더라 양수의 값으로 안될 때 음수를 적용해보아야겠다.
위의 기능을 구현하면서 해당 페이지로 바뀔 때 정보를 전달해줄 방법이 필요했다. 클릭 시 상세페이지로 가는 느낌인데 url에 params를 담아서 보낼 수 있지만 다른 방법을 시도하다가 history.location.state를 활용하였다.
{list.map((el, index) => (
<li
onClick={() => {
history.push('/detail');
history.location.state = el.url;
}}
key={index}
className={cx('img_wrapper')}
>
이렇게 map함수에서 데이터를 리턴해주며 온클릭시 location.state에 해당 정보를 담는다. 그런 후 해당 컴포넌트에서 state를 조회하여 그 값을 사용할 수 있다. params를 활용하기 애매할때 사용하면 될것같은 방법이였다.
특정 타입의 조건에 따라 다른 컴포넌트를 렌더링 해줘야 하는 상황이 생겼다. 어떻게 처리할지 고민하다가 객체로 관리하며 jsx의 특징을 활용해서 다뤄보기로 하였다.
const blockType = {
slider: <DragSlide />,
carousel: <TopCarousel />,
list: <FourFixCard />,
}
이렇게 위와같이 객체의 key값을 타입의 이름으로 지정하고 value를 jsx.element로 지정한 다음
blockType.slider // <DragSlide /> 리턴
blockType.carousel // <TopCarousel /> 리턴
접근을 해준다. 서버에서 해당 타입의 정보를 받는다면
const [data, setData] = useState([]);
const blockType = {
slider: <DragSlide />,
carousel: <TopCarousel />,
list: <FourFixCard />,
};
return {
data.map((el, index) => {
<div key={index}>
{blockType[el.type]}
</div>
}
)
}
이런식으로 접근할 수 있다.
근데 이렇게 하니 해당 컴포넌트에 특정 props를 담을 수 없었다. 그래서 고민하다 객체의 구조를 바꿔보기로 했다.
const blockType = {
slider: (props) => <DragSlide {...props} />,
carousel: (props) => <TopCarousel {...props} />,
list: (props) => <FourFixCard {...props} />,
};
....
<div key={index}>
{blockType[el.component](담을props)}
</div>
위와같이 value를 함수로 만들어서 함수가 리턴할때 props를 담도록 정의해주었다. ts적용에서는
const blockType: {
[key: string]: any,
} = {
slider: (props: BlockProps) => <DragSlide {...props} />,
carousel: (props: BlockProps) => <TopCarousel {...props} />,
list: (props: BlockProps) => <FourFixCard {...props} />,
}
;<div key={index}>{blockType[el.component](el)}</div>
위와 같은 형태로 완성시켰다.
데이터를 받을때 mustache가 들어가 있는 데이터가 있는데 관련 처리 방법.
사전적 의미로는 수염, 콧수염이다 {{ }} 중괄호를 씌운건데, 중괄호 이미지를 눕히면 수염 같아서 그렇게 부르는것 같다.
const mustache = '{{mustache}}'
// data ===> '{{username}} hi'
위와 같은 형태인데 저 중괄호를 실제 username으로 바꿔야 한다면?? 몇가지 방법이 떠올랐는데 갑자기 문득 자바스크립트 replace함수가 머릿속을 스쳐지나갔다.