HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🙂
달리팀 노션
/
👨🏻‍💻
달리 2팀 (deprecated 문제 없으면 삭제 예정)
/
Today We Learned
Today We Learned
/
inline style 적용 시 기존 스타일 미적용 문제
inline style 적용 시 기존 스타일 미적용 문제
inline style 적용 시 기존 스타일 미적용 문제

inline style 적용 시 기존 스타일 미적용 문제

생성일
Nov 9, 2021 03:48 PM
기록자
해결 여부
해결 여부
속성
React
카테고리
이슈

문제

유저 정보 페이지 리팩토링 중, UserImage를 기존 base component 로 대체하고 싶었고, 따라서 Image 컴포넌트를 임포트하였다.
이후, 이미지에 정확히 props를 집어 넣어주었다.
그러나 제대로 동작하지 않았다. 문제가 무엇일까?
notion image
추후 비슷한 상황이 발생할 때, 이를 간단히 참고할 수 있도록 해당 코드를 남겨 놓는다.

Image.js

import React, { useState, useRef, useEffect } from 'react'; let observer = null; const LOAD_IMG_EVENT_TYPE = 'loadImage'; const onIntersection = (entries, io) => { entries.forEach((entry) => { if (entry.isIntersecting) { io.unobserve(entry.target); entry.target.dispatchEvent(new CustomEvent(LOAD_IMG_EVENT_TYPE)); } }); }; const Image = ({ src, placeholder, lazy, threshold = 0.5, block, width, height, alt, mode, isCircle, ...props }) => { const [loaded, setLoaded] = useState(false); const imgRef = useRef(null); const imageStyle = { display: block ? 'block' : undefined, width, height, objectFit: mode, // cover, fill, contain ...(isCircle ? { borderRadius: '50%' } : {}), }; useEffect(() => { if (!lazy) { setLoaded(true); return; } const handleLoadImage = () => setLoaded(true); const imgElement = imgRef.current; imgElement && imgElement.addEventListener(LOAD_IMG_EVENT_TYPE, handleLoadImage); // Arrow function expected no return value. eslint(consistent-return) // eslint-disable-next-line return () => { imgElement && imgElement.removeEventListener(LOAD_IMG_EVENT_TYPE, handleLoadImage); }; }, [lazy]); useEffect(() => { if (!lazy) return; if (!observer) { observer = new IntersectionObserver(onIntersection, { threshold }); } imgRef.current && observer.observe(imgRef.current); }, [lazy, threshold]); return ( <img ref={imgRef} src={loaded && src ? src : placeholder} style={{ ...props.style, ...imageStyle }} alt={alt} {...props} /> ); }; export default Image;
 

UserDetailInfo.js

<Image src={image} placeholder={userPlaceholder} block lazy width={200} height={200} alt="userProfile" isCircle style={{ border: `5px solid ${colors.default.white}` }} />

해결

핵심 원인은 props의 순서였다.
리액트의 style prop은 CSS에서의 selector properties를 반영하기 때문에 inline style을 우선적으로 적용한다.
따라서 다음 가설을 세웠다.
💡
1. style도 엄연한 props이다. 2. 따라서 prop에 style을 추가했다면, style을 선언 후 또 prop를 추가로 setting해준다면, 마지막 {...props}에 들어 있는 prop이 결과적으로 다시 또 update될 것이다. 3. 그렇다면, 결과적으로 마지막 style만 적용되고, imageStyle이 적용되지 않을 것이다.
이러한 생각을 하게 된 이유는, 추가로 지정했던 style만이 반영되었기 때문이다.
 
따라서 이를 제대로 적용하기 위해서는, 다음과 같이 props 배치를 앞으로 해주었어야 했다.

Image.js

return ( <img {...props} ref={imgRef} src={loaded && src ? src : placeholder} style={{ ...props.style, ...imageStyle }} alt={alt} /> );
 

결과

잘 적용된다!
notion image
 

배운 점

  1. props는 왼쪽에서 오른쪽, 윗쪽에서 아랫쪽 순서대로 읽는다.
    1. 이건 설마설마 했는데, 정말로 그렇더라. 앞으로 단순히 배치할 게 아니말아야겠다. 혹여나 발생할 수 있는 사이드 이펙트에 따른 우선순위에 따라서 배치해야겠다고 생각했다!
  1. 리액트도 CSS 기반 선택자 우선순위에 따른 style 규칙을 잘 반영했다.
    1. 결국 인라인 스타일의 우선 순위를 제대로 반영했다고 본다. (레온 강사님의 말씀에 따르면, 인라인 규칙의 우선 순위는 1000점)이니, CSS in JS에서 나중에 !important로도 우선순위를 바꿀 수 있는지 테스트 해봐야겠다.