<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>analogcoding</title>
    <link>https://analogcoding.tistory.com/</link>
    <description>contact

E-mail : wjsdbtjs131313@gmail.com
Insta    : gucci0419
</description>
    <language>ko</language>
    <pubDate>Thu, 23 Jul 2026 01:45:24 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>be well</managingEditor>
    <image>
      <title>analogcoding</title>
      <url>https://tistory1.daumcdn.net/tistory/3067517/attach/edce7c3be71a4e8f9b98771a056f4198</url>
      <link>https://analogcoding.tistory.com</link>
    </image>
    <item>
      <title>react SEO , prerender</title>
      <link>https://analogcoding.tistory.com/200</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;prerender 의 주요 장점은 각 페이지의 핵심 내용을 크롤러가 얻을 수 있다는 것 뿐만 아니라&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;브라우저는 JS 파일이 렌더링을 시작하기 위해로드 될 때까지 기다릴 필요가 없으므로&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;SEO&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;뿐만 아니라 성능상의 이점도 존재한다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SSR&amp;nbsp;&lt;/b&gt;을 사용하지 않고 &lt;b&gt;SEO&lt;/b&gt; 최적화 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-helmet 과 react-snap&amp;nbsp; 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;react-helmet&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-helmet&quot;&gt;https://www.npmjs.com/package/react-helmet&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1592290409593&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;react-helmet&quot; data-og-description=&quot;A document head manager for React&quot; data-og-host=&quot;www.npmjs.com&quot; data-og-source-url=&quot;https://www.npmjs.com/package/react-helmet&quot; data-og-url=&quot;https://www.npmjs.com/package/react-helmet&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/M3E0p/hyGrD9DObt/VsP4uo2bWQEOFcG9yt6A0k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/zep1E/hyGrDu2W7q/aT4G2roSOUalOKfbxQXYp1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-helmet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.npmjs.com/package/react-helmet&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/M3E0p/hyGrD9DObt/VsP4uo2bWQEOFcG9yt6A0k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/zep1E/hyGrDu2W7q/aT4G2roSOUalOKfbxQXYp1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;react-helmet&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A document head manager for React&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.npmjs.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spa 에서 각 route 마다 html head 를 설정할 수 있게 도와준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1592290664486&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import { Helmet } from &quot;react-helmet&quot;;

interface MyHelmetProps {
  title: string;
  description?: string;
}

const MyHelmet = ({ title, description }: MyHelmetProps) =&amp;gt; {
  return (
    &amp;lt;Helmet&amp;gt;
      &amp;lt;meta charSet=&quot;utf-8&quot; /&amp;gt;
      {description &amp;amp;&amp;amp; &amp;lt;meta name=&quot;description&quot; content={description} /&amp;gt;}
      &amp;lt;title&amp;gt;{title}&amp;lt;/title&amp;gt;
    &amp;lt;/Helmet&amp;gt;
  );
};

export default MyHelmet;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 컴포넌트화 해서 사용하면 더 좋지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;react-snap&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;script 에 추가하고 build 시 각 route 마다 index.html 을 생성해준다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-dom 에서 hydrate 를 사용해서 비교&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-filename=&quot;스크린샷 2020-06-16 오후 3.58.52.png&quot; data-origin-width=&quot;191&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOvjqC/btqERQZOAtC/UmXgzAGbDiSydc0F4fSZlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOvjqC/btqERQZOAtC/UmXgzAGbDiSydc0F4fSZlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOvjqC/btqERQZOAtC/UmXgzAGbDiSydc0F4fSZlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOvjqC%2FbtqERQZOAtC%2FUmXgzAGbDiSydc0F4fSZlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;191&quot; height=&quot;402&quot; data-filename=&quot;스크린샷 2020-06-16 오후 3.58.52.png&quot; data-origin-width=&quot;191&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1592290826475&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; &quot;scripts&quot;: {
    &quot;start&quot;: &quot;react-scripts start&quot;,
    &quot;build&quot;: &quot;react-scripts build&quot;,
    &quot;test&quot;: &quot;react-scripts test&quot;,
    &quot;eject&quot;: &quot;react-scripts eject&quot;,
    &quot;postbuild&quot;: &quot;react-snap&quot;
  },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;package.json&amp;nbsp; &lt;/b&gt;script 에 추가&lt;/p&gt;
&lt;pre id=&quot;code_1592290875436&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import { hydrate, render } from &quot;react-dom&quot;;
import Router from &quot;./Router&quot;;


const rootElement = document.getElementById(&quot;root&quot;);

if (!!rootElement &amp;amp;&amp;amp; rootElement.hasChildNodes()) {
  hydrate(
    &amp;lt;React.StrictMode&amp;gt;
      &amp;lt;Router /&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;,
    rootElement
  );
} else {
  render(
    &amp;lt;React.StrictMode&amp;gt;
      &amp;lt;Router /&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;,
    rootElement
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;react-dom 에서 hydrate 를 사용해서 비교 후 렌더링한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 자료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/stereobooster/react-snap&quot;&gt;https://github.com/stereobooster/react-snap&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1592290479432&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;stereobooster/react-snap&quot; data-og-description=&quot;  Zero-configuration framework-agnostic static prerendering for SPAs - stereobooster/react-snap&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/stereobooster/react-snap&quot; data-og-url=&quot;https://github.com/stereobooster/react-snap&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bdYASb/hyGrCv70jF/UdUJd3VKQn1HMPKokSAdQ1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://github.com/stereobooster/react-snap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/stereobooster/react-snap&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bdYASb/hyGrCv70jF/UdUJd3VKQn1HMPKokSAdQ1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;stereobooster/react-snap&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  Zero-configuration framework-agnostic static prerendering for SPAs - stereobooster/react-snap&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/react-dom.html#hydrate&quot;&gt;https://ko.reactjs.org/docs/react-dom.html#hydrate&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1592290577327&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ReactDOM &amp;ndash; React&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;ko.reactjs.org&quot; data-og-source-url=&quot;https://ko.reactjs.org/docs/react-dom.html#hydrate&quot; data-og-url=&quot;https://ko.reactjs.org/docs/react-dom.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cB3cbz/hyGrBKKIpx/7wKJj6kaKQVpcMhD8H8L3k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/react-dom.html#hydrate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.reactjs.org/docs/react-dom.html#hydrate&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cB3cbz/hyGrBKKIpx/7wKJj6kaKQVpcMhD8H8L3k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ReactDOM &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.reactjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/46516395/whats-the-difference-between-hydrate-and-render-in-react-16&quot;&gt;https://stackoverflow.com/questions/46516395/whats-the-difference-between-hydrate-and-render-in-react-16&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1592290622749&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;What's the difference between hydrate() and render() in React 16?&quot; data-og-description=&quot;I've read the documentation, but I didn't really understand the difference between hydrate() and render() in React 16. I know hydrate() is used to combine SSR and client-side rendering. Can someone&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/46516395/whats-the-difference-between-hydrate-and-render-in-react-16&quot; data-og-url=&quot;https://stackoverflow.com/questions/46516395/whats-the-difference-between-hydrate-and-render-in-react-16&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/78Zuu/hyGrx2EYNW/UCHkdBgxvJhlCvzUIWa0AK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/46516395/whats-the-difference-between-hydrate-and-render-in-react-16&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/46516395/whats-the-difference-between-hydrate-and-render-in-react-16&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/78Zuu/hyGrx2EYNW/UCHkdBgxvJhlCvzUIWa0AK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;What's the difference between hydrate() and render() in React 16?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I've read the documentation, but I didn't really understand the difference between hydrate() and render() in React 16. I know hydrate() is used to combine SSR and client-side rendering. Can someone&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://create-react-app.dev/docs/pre-rendering-into-static-html-files/&quot;&gt;https://create-react-app.dev/docs/pre-rendering-into-static-html-files/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1592287760846&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Create React App &amp;middot; Set up a modern web app by running one command.&quot; data-og-description=&quot;If you&amp;rsquo;re hosting your &amp;#96;build&amp;#96; with a static hosting provider you can use [react-snapshot](https://www.npmjs.com/package/react-snapshot) or [react-snap](https://github.com/stereobooster/react-snap) to generate HTML pages for each route, or relative link,&quot; data-og-host=&quot;create-react-app.dev&quot; data-og-source-url=&quot;https://create-react-app.dev/docs/pre-rendering-into-static-html-files/&quot; data-og-url=&quot;https://create-react-app.dev/docs/pre-rendering-into-static-html-files&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QS7xD/hyGrBKI3uB/kWrGe6BWRWYwj2JVltovhK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bzSKEW/hyGqlpeIDq/YoxI5A5Z0dIPtvRHRdg6a0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://create-react-app.dev/docs/pre-rendering-into-static-html-files/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://create-react-app.dev/docs/pre-rendering-into-static-html-files/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QS7xD/hyGrBKI3uB/kWrGe6BWRWYwj2JVltovhK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bzSKEW/hyGqlpeIDq/YoxI5A5Z0dIPtvRHRdg6a0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Create React App &amp;middot; Set up a modern web app by running one command.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;If you&amp;rsquo;re hosting your `build` with a static hosting provider you can use [react-snapshot](https://www.npmjs.com/package/react-snapshot) or [react-snap](https://github.com/stereobooster/react-snap) to generate HTML pages for each route, or relative link,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;create-react-app.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Be well coding/Mine</category>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/200</guid>
      <comments>https://analogcoding.tistory.com/200#entry200comment</comments>
      <pubDate>Tue, 16 Jun 2020 16:01:46 +0900</pubDate>
    </item>
    <item>
      <title>React Hook life cycle</title>
      <link>https://analogcoding.tistory.com/199</link>
      <description>&lt;h2 id=&quot;componentdidmount&quot;&gt;ComponentDidMount&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;컴포넌트가 만들어지고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;render&lt;span&gt;가 호출된 이후에 호출되는 메소드. ( example : fetch or TImer )&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1591258647393&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Class
class Example extends React.Component {
    componentDidMount() {
        ...
    }
}

// Hook
const Example = () =&amp;gt; {
    useEffect(() =&amp;gt; {
        ...
    }, []);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;componentwillunmount&quot;&gt;ComponentWillUnmount&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;React 엘리먼트를 실제 DOM 노드에 추가하기 직전에 호출되는 메소드.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;DOM이 생성되지 않았으므로 DOM을 조작할 수 없고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;render&lt;span&gt;가 호출되기 전이기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;setState를 사용해도&lt;span&gt;&amp;nbsp;&lt;/span&gt;render가 호출하지 않음.&lt;/p&gt;
&lt;pre id=&quot;code_1591258663424&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Class
class Example extends React.Component {
    componentWillUnmount() {
        ...
    }
}

// Hook
const Example = () =&amp;gt; {
    useEffect(() =&amp;gt; {
        return () =&amp;gt; {
            ...
        };
    }, []);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hook 에서는 useEffect 에서 함수를 리턴하는 형태로 구현&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;componentwillreceivepropsnextprops&quot;&gt;componentWillReceiveProps(nextProps&lt;/h3&gt;
&lt;p&gt;&lt;span&gt;컴포넌트 생성후에 첫 렌더링을 마친 후 호출되는 메서드. (&lt;span style=&quot;color: #333333;&quot;&gt;컴포넌트가 처음 마운트 되는 시점에서는 호출되지 않음&lt;/span&gt;&lt;b&gt;.&lt;/b&gt;)&lt;/span&gt;&lt;br /&gt;이 메소드 내부에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;setState를 사용해도 추가적인 렌더링이 발생하지 않음.&lt;br /&gt;(example : &lt;span style=&quot;color: #333333;&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;를 받아서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;를 변경해야 하는 경우&amp;nbsp;&lt;/span&gt;)&lt;/p&gt;
&lt;pre id=&quot;code_1591258770065&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Class
class Example extends React.Component {
    componentWillReceiveProps(nextProps) {
        ...
    }
    or
    UNSAFE_componentWillReceiveProps(nextProps) {
        ...
    }
}

// Hook
const Example = (props) =&amp;gt; {
    const { value } = props;
    useEffect(() =&amp;gt; {
        ...
    }, [value]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;shouldcomponentupdate&quot;&gt;ShouldComponentUpdate&lt;/h2&gt;
&lt;p&gt;shouldComponentUpdate&lt;span&gt;가 불린 이후에 컴포넌트 업데이트 직전에서 호출되는 메소드.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;새로운 props 또는 state가 반영되기 직전 새로운 값들을 받음.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;이 메서드 안에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;this.setState()를 사용하면 무한 루프가 일어나게 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;b&gt;주의&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;class 컴포넌트의 shouldComponentUpdate() 메서드와 달리, areEqual 함수는 props들이 서로 같으면 true를 반환하고, props들이 서로 다르면 false를 반환한다. 이것은 shouldComponentUpdate와 정반대의 동작이다.&lt;/p&gt;
&lt;pre id=&quot;code_1591258893085&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Class
class Example extends React.Component {
    shouldComponentUpdate(nextProps) {
        return nextProps.value !== this.props.value;
    }
}

// Hook
const Example = React.memo(() =&amp;gt; {
    ...
}, (prevProps, nextProps) =&amp;gt; {
    return nextProps.value === prevProps.value;
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Be well coding/Learn more</category>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/199</guid>
      <comments>https://analogcoding.tistory.com/199#entry199comment</comments>
      <pubDate>Thu, 4 Jun 2020 17:39:55 +0900</pubDate>
    </item>
    <item>
      <title>React useRef 사용하기</title>
      <link>https://analogcoding.tistory.com/198</link>
      <description>&lt;p&gt;Change Scroll&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Multiple Input Focus&lt;/p&gt;</description>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/198</guid>
      <comments>https://analogcoding.tistory.com/198#entry198comment</comments>
      <pubDate>Thu, 4 Jun 2020 11:14:45 +0900</pubDate>
    </item>
    <item>
      <title>react 에서 SVG 아이콘 컴포넌트로 사용하기.</title>
      <link>https://analogcoding.tistory.com/197</link>
      <description>&lt;p&gt;svg 파일을 추가하면 element 형태로 나타나는데 이를 컴포넌트화해서 사용하는 방법이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1590711874723&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Logo = ({ color = &quot;#080405&quot;, width = 80, height = 120 }: LogoProps) =&amp;gt; (
  &amp;lt;svg
    xmlns=&quot;http://www.w3.org/2000/svg&quot;
    viewBox=&quot;0 0 2929.35 1662.66&quot;
    style={{ width, height }}
  &amp;gt;
  
  ...
  
  &amp;lt;/svg&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;원하는 색상과 크기에 맞춰 사용할 수 있게 컴포넌트화해서 사용.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;크기는 style 속성으로 컨트롤하고 색상은 path 부분에 fill 에 적용.&lt;/p&gt;</description>
      <category>Be well coding/Mine</category>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/197</guid>
      <comments>https://analogcoding.tistory.com/197#entry197comment</comments>
      <pubDate>Fri, 29 May 2020 09:25:41 +0900</pubDate>
    </item>
    <item>
      <title>react + typescript 절대경로 import</title>
      <link>https://analogcoding.tistory.com/196</link>
      <description>&lt;p&gt;&lt;span&gt;babel-plugin-module-resolver 플러그인 추가&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;babel.config.js 해당 플러그인 추가 후 alias 에 별칭&amp;nbsp; : 주소 형태로 저장&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589515869111&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins: [
    [
      'module-resolver',
      {
        root: ['.'],
        alias: {
          '~': './src',
          '~buttons': '.src/components/buttons',
        },
      },
    ],
  ],

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;tsconfig 에 baseUrl 과 paths 추가&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589515828519&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;baseUrl&quot;: &quot;./src&quot;
    &quot;paths&quot;: {
      &quot;~/*&quot;: [&quot;./*&quot;],
      &quot;~buttons/*&quot;: [&quot;components/buttons/*&quot;]
    },&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Be well coding/Mine</category>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/196</guid>
      <comments>https://analogcoding.tistory.com/196#entry196comment</comments>
      <pubDate>Fri, 15 May 2020 13:11:43 +0900</pubDate>
    </item>
    <item>
      <title>error Failed to build iOS project. We ran &amp;ldquo;xcodebuild&amp;rdquo; command but it exited with error code 65</title>
      <link>https://analogcoding.tistory.com/195</link>
      <description>&lt;p&gt;#&amp;nbsp;error&amp;nbsp;Failed&amp;nbsp;to&amp;nbsp;build&amp;nbsp;iOS&amp;nbsp;project.&amp;nbsp;We&amp;nbsp;ran&amp;nbsp;&amp;ldquo;xcodebuild&amp;rdquo;&amp;nbsp;command&amp;nbsp;but&amp;nbsp;it&amp;nbsp;exited&amp;nbsp;with&amp;nbsp;error&amp;nbsp;code&amp;nbsp;65&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;stackoverflow 어지간한 거 다 해봤지만 실패 후&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;ㄴ&amp;nbsp;같은&amp;nbsp;이름으로&amp;nbsp;새&amp;nbsp;프로젝트&amp;nbsp;생성&amp;nbsp;후&amp;nbsp;ios&amp;nbsp;폴더&amp;nbsp;삭제&amp;nbsp;후&amp;nbsp;해당&amp;nbsp;프로젝트에&amp;nbsp;ios&amp;nbsp;폴더를&amp;nbsp;추가&amp;nbsp;이&amp;nbsp;후&amp;nbsp;pod&amp;nbsp;install&amp;nbsp;로&amp;nbsp;해결&lt;/p&gt;</description>
      <category>Be well coding/Mine</category>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/195</guid>
      <comments>https://analogcoding.tistory.com/195#entry195comment</comments>
      <pubDate>Mon, 11 May 2020 18:07:45 +0900</pubDate>
    </item>
    <item>
      <title>React Hooks 에서 lifecycle 사용하기</title>
      <link>https://analogcoding.tistory.com/192</link>
      <description>&lt;p&gt;리액트 훅스에서 side effect 로 라이프사이클을 조정할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;리액트 훅스에서 기존 생명주기 메소드 (componentDidMount, componentDidUpdate, componentWillUnmount 등의 이펙트를&lt;/p&gt;
&lt;p&gt;함수형 컴포넌트에서 사용하는 것에 대해 다시 한 번 정리한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;componentDidMount&lt;/b&gt;&lt;span&gt; =&amp;gt; &lt;/span&gt;컴포넌트가 마운트 될 때 한 번 실행된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1588050363619&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; { 
// Your code here 
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;두 번째 매개 변수로 &lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt; &lt;/span&gt;빈 배열을 주면 어떤 값을 감지할 때 렌더되는 것을 막기 때문에 처음 한 번만 실행된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;두 번째 매개 변수없이&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;useEffect 사용 시 모든 렌더에서 호출되므로 주의.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1588050430733&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
 // Your code here 
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;componentWillUnmount 는 정리에 사용된다. (이벤트 리스너 제거, 타이머 취소 등)&lt;/p&gt;
&lt;p&gt;componentDidMount 에 이벤트 리스터를 추가하고 아래와 같이 componentWillUnmount 에서&lt;/p&gt;
&lt;p&gt;이벤트 리미터를 제거하는 것.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1588050551683&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;componentDidMount() { 
	window.addEventListener('mousemove', () =&amp;gt; {}) 
} 

componentWillUnmount() { 
	window.removeEventListener('mousemove', () =&amp;gt; {}) 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위 코드와 동등한 훅스에 이펙트는 아래처럼 구현한다.&lt;/p&gt;
&lt;pre id=&quot;code_1588050606843&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; { 
	window.addEventListener('mousemove', () =&amp;gt; {}); 
    // returned function will be called on component unmount 

	return () =&amp;gt; { 
		window.removeEventListener('mousemove', () =&amp;gt; {}) } 
}, [])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span&gt;다음과 같이 return 에 함수를 주면 컴포넌트가 unmount 될 때 함수를 실행한다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;위에 언급한 것처럼 일반적으로 eventListner의 역할을 다하면 다시 remove할때 이 useEffect의 return값을 이용한다 .&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Reactjs.org에 따르면 componentWillMount는 향후 지원되지 않을 것이다?!&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/react-component.html#unsafe_componentwillmount&quot;&gt;https://reactjs.org/docs/react-component.html#unsafe_componentwillmount&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1588050694819&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;React.Component &amp;ndash; React&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;reactjs.org&quot; data-og-source-url=&quot;https://reactjs.org/docs/react-component.html#unsafe_componentwillmount&quot; data-og-url=&quot;https://reactjs.org/docs/react-component.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/tke8E/hyFQUcVtQZ/xuER8k0iz8hIfzkvL5WLi1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://reactjs.org/docs/react-component.html#unsafe_componentwillmount&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://reactjs.org/docs/react-component.html#unsafe_componentwillmount&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/tke8E/hyFQUcVtQZ/xuER8k0iz8hIfzkvL5WLi1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;React.Component &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;reactjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;ComponentWillMount를 요청하는 이유는 렌더링 전에 상태를 초기화하려고하기 때문일 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 부분은 UseState에서 initState 를 설정해서 초기화 할 수 있다.&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1588050758723&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const helloWorld=()=&amp;gt;{ 
	const [value,setValue]=useState(0) //initialize your state here 


return &amp;lt;p&amp;gt;{value}&amp;lt;/p&amp;gt; } 

export default helloWorld;

&lt;/code&gt;&lt;/pre&gt;
&lt;hr style=&quot;box-sizing: content-box; height: 0px; overflow: visible; margin-top: 1rem; margin-bottom: 1rem; border-width: 1px 0px 0px; border-image: initial; border-color: rgba(0, 0, 0, 0.1) initial initial initial; border-style: solid initial initial initial;&quot; /&gt;
&lt;p&gt;&lt;b&gt;2019 년 8 월 21 일에 업데이트 됨&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;useEffect 를 didmount 처럼 사용할 때 ( &lt;span style=&quot;color: #333333;&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;)&lt;/span&gt; )&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;React는 배열 []에 전달한 값을 비교할 때 Object.is ()를 사용하여 비교한다. 객체를 전달하면&lt;/p&gt;
&lt;p&gt;&lt;span&gt;useEffect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;name&lt;span&gt;:&lt;/span&gt;&lt;span&gt;'Tom'&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이것은 다음과 같이 동작한다 :&lt;/p&gt;
&lt;p&gt;&lt;span&gt;useEffect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Object.is ()가 객체를 비교할 때 &lt;b&gt;값 자체&lt;/b&gt;가 아닌 &lt;b&gt;참조&lt;/b&gt;를 비교하기 때문에 매번 다시 렌더링된다.&lt;/p&gt;
&lt;p&gt;참조하는 객체가 다르기 때문에 {} === {}가 false를 반환하는 이유와 동일.&lt;/p&gt;
&lt;p&gt;여전히 참조 객체가 아닌 객체 자체를 비교하려면 다음과 같이 비교한다.&lt;/p&gt;
&lt;pre id=&quot;code_1588050913904&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(()=&amp;gt;{},[JSON.stringify({name:'Tom'})])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/192</guid>
      <comments>https://analogcoding.tistory.com/192#entry192comment</comments>
      <pubDate>Tue, 28 Apr 2020 14:15:43 +0900</pubDate>
    </item>
    <item>
      <title>StoryBook 사용 - 번역</title>
      <link>https://analogcoding.tistory.com/191</link>
      <description>&lt;h1&gt;스토리북을 통한 리액트 컴포넌트 도큐멘팅&lt;/h1&gt;
&lt;p&gt;(출저 : &lt;a href=&quot;https://medium.com/@emmabostian/documenting-react-components-with-storybook-6c83abe7cb29&quot;&gt;https://medium.com/@emmabostian/documenting-react-components-with-storybook-6c83abe7cb29&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*jGJ3v3RWYEWwFWh-5kjxSg.png&quot; alt=&quot;img&quot;&gt;&lt;/p&gt;
&lt;h2&gt;스토리 북이란?&lt;/h2&gt;
&lt;p&gt;스토리 북은 UI 컴포넌트를 위한 놀이터로 시장을 주도하고 있으며 주요 내용은 &amp;quot;스토리 작성&amp;quot;입니다.&lt;br&gt;스토리 북은 스토리 개념을 사용하여 구성 요소를 문서화합니다.&lt;br&gt;일반적으로 스토리에는 시각적 테스트 사례와 같은 단일 컴포넌트의 상태가 포함됩니다.&lt;br&gt;기술적으로 스토리는 화면에 렌더링 할 수있는 것을 반환하는 함수입니다.&lt;br&gt;컴포넌트 스토리 북에는 다양한 컴포넌트에 대한 다양한 스토리가 포함됩니다.&lt;br&gt;우리가 작성하는 각 스토리에는 다음과 같은 단일 상태가 포함됩니다.&lt;/p&gt;
&lt;p&gt;Storybook의 장점은 React, Vue, React Native, Angular 등과 같은 많은 인기있는 프런트 엔드 프레임 워크 및 라이브러리와 함께 작동한다는 것입니다.&lt;/p&gt;
&lt;p&gt;설정&lt;br&gt;이 튜토리얼에서는 2019 년 5 월 ReactJS Girls London에서 제공 한 React 강연을 통해 건물 설계 시스템에 스토리 북을 추가 할 예정입니다.&lt;br&gt;코드를 따르거나 &lt;a href=&quot;https://github.com/emmabostian/react-button&quot;&gt;저장소&lt;/a&gt; 에서 최종 코드를 확인하실 수 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;프로젝트 디렉토리로 변경하고 종속성을 설치하십시오 (필요한 경우).&lt;br&gt;나는 디렉토리를 변경하지 않아서 왜 아무것도 작동하지 않는지 알아 내려고 10 분을 버렸습니다..&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;그런 다음 Storybook 용 상용구 파일을 설치하십시오. (다운로드하는 데 1 초가 걸립니다. 그 동안 신선한 커피를 마시고 싶을 것입니다.)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cd my-project npx -p @storybook/cli sb init&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;이 도구는 package.json 파일을 체크 아웃하여 사용중인 프레임 워크 또는 라이브러리 (보기 계층)를 결정합니다.&lt;br&gt;자동 검색이 실패하거나 HTML 용 Storybook을 사용하려면 다음 명령을 사용하십시오.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;px -p @storybook/cli sb init --type html | &amp;lt;other-type&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;install 이 끝나면 아래 커맨드로 스토리북을 실행하세요.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;npm run storybook&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;실행되면 localhost 에 이런 창이 뜰 것 입니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*wwLGjl_5V9oaxokCNYMyPw.png&quot; alt=&quot;storybook&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;이제 스토리 북을 프로젝트 내 개발 의존성으로 추가하려고합니다. 다음 명령을 실행하여 이를 수행 할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;npm install @ storybook / react --save-dev&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;스토리 북에는 몇 가지 종속성이 있으며 설치해야합니다. react 및 react-dom 일반 의존성으로 저장해야합니다. @babel/core및 babel-loader개발 종속성으로 저장해야합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;npm install react-dom --save&lt;/code&gt;&lt;br&gt;&lt;code&gt;npm install babel-loader @ babel / core --save-dev&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;npm스토리 북을 쉽게 시작할 수 있도록 스크립트를 추가하고 싶습니다. package.json파일 안에 storybook스크립트를 추가하겠습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;{&lt;br&gt;&amp;quot;script&amp;quot;: {&lt;br&gt;&amp;quot;storybook&amp;quot;: &amp;quot;start-storybook&amp;quot;&lt;br&gt;}&lt;br&gt;}&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;마지막으로, 스토리 북 구성 파일을 작성하여 스토리 북에 스토리를 작성할 위치를 알려줍니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이전 단계에서 이 파일을 이미 작성했을 가능성이 높지만 그렇지 않은 경우 폴더 config.js내에 새 파일을 작성하십시오 &lt;code&gt;storybook/&lt;/code&gt;.&lt;br&gt;내 &lt;code&gt;config.js&lt;/code&gt;파일에는 다음이 포함되어 있습니다.&lt;/p&gt;
&lt;p&gt;이것은 스토리 북이 src 폴더 내부에서 &lt;code&gt;src/stories&lt;/code&gt; 이처럼 보도록 지시 합니다.&lt;/p&gt;
&lt;h2&gt;문서화&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;개발 서버가 npm run storybook 으로 실행 중인지 확인하십시오.&lt;/li&gt;
&lt;li&gt;먼저의 내부에서 상용구를 제거합니다. &lt;code&gt;src/stories/index.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;이제 첫 번째 컴포넌트를 가져 오겠습니다. 내 프로젝트의 경우 Button 구성 요소를 가져옵니다. src/폴더 안에 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;import Button from &amp;#39;../Button&amp;#39;;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;버튼 유형을 설명하기 위해 열거 형을 사용하고 있으므로 버튼을 가져올 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;import { ButtonTypes } from &amp;quot;../buttonTypes&amp;quot;;&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;우리는 이제 우리의 첫 번째 storiesOf 버튼을 쓰고 싶습니다. 1 차, 2 차 및 3 차의 세 가지 상태로 시작하겠습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;각 상태를 추가 하려면 .add()함수를 사용해야 합니다.&lt;br&gt;여기에는 추가하려는 state 이름과 컴포넌트를 반환하는 함수라는 두 가지 인수가 사용됩니다.&lt;/p&gt;
&lt;p&gt;UI에서이를 확인하면 1 차, 2 차 및 3 차의 3가지 상태가있는 Button이라는 스토리가 표시됩니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*jNWN3RldHeW4U5Z7oxtQOw.png&quot; alt=&quot;storybookUI&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;이제는 효과가 있으므로 스토리를 조금 더 잘 모듈화하고 싶습니다. 엔터프라이즈 응용 프로그램이나 전체 디자인 시스템에서이 작업을 수행 한 경우 컴포넌트 옆에 스토리를 추가합니다. 그러나 이것이 개념 증명이라는 사실 때문에 stories/폴더 안에 추가 할 것 입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;src/stories/&lt;/code&gt;안에 &lt;code&gt;buttonStories.js&lt;/code&gt;파일을 만들겠습니다 .&lt;br&gt;다음으로 &lt;code&gt;index.js&lt;/code&gt;파일 의 모든 코드를 복사 하여 새 파일에 붙여 넣습니다 .&lt;br&gt;마지막으로 &lt;code&gt;buttonStories.js&lt;/code&gt; 파일을 &lt;code&gt;index.js&lt;/code&gt; 에서 가져 오기 위해 업데이트 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;import &amp;quot;./buttonStories&amp;quot;;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;이게 다에요! 이제 당신은 컴포넌트와 스테이트로 스토리를 만들어 문서화 할 수 있습니다.&lt;/p&gt;</description>
      <category>Be well coding/Learn more</category>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/191</guid>
      <comments>https://analogcoding.tistory.com/191#entry191comment</comments>
      <pubDate>Tue, 28 Apr 2020 12:48:00 +0900</pubDate>
    </item>
    <item>
      <title>typescript 에서 storybook 사용하기</title>
      <link>https://analogcoding.tistory.com/190</link>
      <description>&lt;p&gt;웹팩 + 타입스크립트 + 리액트 + styled components 로 진행 중인 프로젝트에 storybook 도입을 시도했다.&lt;/p&gt;
&lt;p&gt;참고문서&lt;br /&gt;&lt;a href=&quot;https://velog.io/@velopert/storybook-typescript-props-documentation&quot;&gt;Ts+storybook&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;px -p @storybook/cli sb init&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;스토리북 설치&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.storybook/webpack.config.js&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;생성된 스토리북 폴더에 webpack module 추가&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;module.exports = ({ config, mode }) =&amp;gt; {
  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    use: [
      {
        loader: require.resolve(&quot;babel-loader&quot;),
        options: {
          presets: [[&quot;react-app&quot;, { flow: false, typescript: true }]],
        },
      },
      require.resolve(&quot;react-docgen-typescript-loader&quot;),
    ],
  });
  config.resolve.extensions.push(&quot;.ts&quot;, &quot;.tsx&quot;);
  return config;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ts 및 tsx 확장자에 대하여 babel-loader 와 react-docgen-typescript-loader 를 사용하도록 설정한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.storybook/config.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;import { configure } from '@storybook/react';

configure(require.context('../src', true, /\.stories\.(js|mdx|tsx)$/), module);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;tsx 파일도 Storybook에서 처리하도록 코드를 수정&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/typings.d.ts&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;declare module '*.mdx';&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;추후 ts 파일에서 mdx 확장자로 이루어진 파일을 불러오게 될 때 모듈이 없다는 에러를 방지.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Button 컴포넌트를 모아둔 폴더에 Buttons.stroies.tsx 파일 생성&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import * as React from &quot;react&quot;;
import { DefaultBtn, StyledBtn } from &quot;./Buttons&quot;;

export default {
  title: &quot;components|Button&quot;,
  component: DefaultBtn,
};

// title 은 상위 폴더가 되고 | 뒤에 내용이 하위 폴더로 추가된다.

export const defaultbtn = () =&amp;gt; {
  return (
    &amp;lt;DefaultBtn theme={{ width: 300, height: 50, fontSize: 16 }}&amp;gt;
      이메일 로그인
    &amp;lt;/DefaultBtn&amp;gt;
  );
};

defaultbtn.story = {
  name: &quot;defaultBtn&quot;,
};

// 추가될 스토리의 이름을 설정한다.

export const googleLoginBtn = () =&amp;gt; {
  return (
    &amp;lt;StyledBtn
      theme={{
        width: 300,
        height: 50,
        fontSize: 16,
        radius: 5,
        backGroundColor: &quot;#dd4b39&quot;,
        color: &quot;white&quot;,
      }}
    &amp;gt;
      Google 로그인
    &amp;lt;/StyledBtn&amp;gt;
  );
};

googleLoginBtn.story = {
  name: &quot;googleLoginBtn&quot;,
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;화면에 story code 가 나오는데 이것은 추가로 모듈을 설치해야 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-04-28 오후 1.31.57.png&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwkVwV/btqDLE6BdP5/7jz9Gav8Y3dhywl413LZk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwkVwV/btqDLE6BdP5/7jz9Gav8Y3dhywl413LZk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwkVwV/btqDLE6BdP5/7jz9Gav8Y3dhywl413LZk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwkVwV%2FbtqDLE6BdP5%2F7jz9Gav8Y3dhywl413LZk0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-04-28 오후 1.31.57.png&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;727&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;스토리 소스 에드온을 추가&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1588048513852&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i @storybook/addon-storysource&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;.storybook/&lt;a href=&quot;main.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;main.js&lt;/a&gt; 에 addons 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1588048625633&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {

stories: [&quot;../stories/**/*.stories.js&quot;],

addons: [

&quot;@storybook/addon-actions&quot;,

// &quot;@storybook/addon-links&quot;,

&quot;@storybook/addon-storysource&quot;,

],

webpackFinal: async (config) =&amp;gt; {

// do mutation to the config



return config;

},

};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마지막으로 webpack.config.js 부분 rules 에 아래 코드를 추가하면 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1588048497248&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; (module.exports = function({ config }) {
        config.module.rules.push({
          test: /\.stories\.tsx?$/,
          loaders: [
            {
              loader: require.resolve(&quot;@storybook/source-loader&quot;),
              options: { parser: &quot;typescript&quot; },
            },
          ],
          enforce: &quot;pre&quot;,
        });

        return config;
      }),&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음에는 action 까지 추가해보는 걸로!&lt;/p&gt;</description>
      <category>Be well coding/Mine</category>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/190</guid>
      <comments>https://analogcoding.tistory.com/190#entry190comment</comments>
      <pubDate>Tue, 28 Apr 2020 12:47:33 +0900</pubDate>
    </item>
    <item>
      <title>Github action 을 이용한 S3 배포 - 번역</title>
      <link>https://analogcoding.tistory.com/189</link>
      <description>&lt;h1&gt;React 앱을 S3 에 Github Action 으로 배포하기.&lt;/h1&gt;
&lt;p&gt;(출저 : &lt;a href=&quot;https://medium.com/trackstack/deploying-a-react-app-to-aws-s3-with-github-actions-b1cb9ba75c95&quot;&gt;https://medium.com/trackstack/deploying-a-react-app-to-aws-s3-with-github-actions-b1cb9ba75c95&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*cta8C01-zZukz401wkvrMg.jpeg&quot; alt=&quot;img&quot;&gt;&lt;/p&gt;
&lt;p&gt;Github Actions는 버전 관리 외에 프로젝트 관리 측면을 열어 놓은 Github 의 비교적 새로운 기능입니다.&lt;br&gt;이러한 기능 중 하나는 작년에 이미 혼잡한 시장에 도입 된 CI / CD (Continuous Deployment)입니다.&lt;br&gt;그러나 이 기능에서 볼 수 있는 주요 이점은 모든 배포 요구를 처리하는 단일 서비스입니다.&lt;/p&gt;
&lt;p&gt;이 게시물에서는 Github Actions로 기본 연속 배포 파이프 라인을 설정하여 React 앱을 AWS S3에 배포하는 단계를 간략하게 설명합니다.&lt;br&gt;복잡하지 않은 방법을 알려 드리겠습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;스테이징 및 프로덕션 인스턴스를 위한 설정 워크 플로우 파일 생성&lt;/li&gt;
&lt;li&gt;Github에 AWS secret 추가&lt;/li&gt;
&lt;li&gt;S3 버킷에 파일을 배포하는 Github Action 설치&lt;/li&gt;
&lt;li&gt;S3 버킷에 React 앱 배포&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;기본 설정 :&lt;/h2&gt;
&lt;p&gt;처음에는 React 앱을 설정하고 Github에 푸시하는 방법을 알고 있다고 가정합니다.&lt;br&gt;그렇지 않다면 &lt;a href=&quot;https://reactjs.org/docs/create-a-new-react-app.html&quot;&gt;여기&lt;/a&gt; 와 &lt;a href=&quot;https://help.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line&quot;&gt;여기&lt;/a&gt; 에서 시작할 수 있습니다 .&lt;br&gt;앱이 준비되면 두 가지 방법으로 작업 워크 플로우를 시작할 수 있습니다.&lt;br&gt;첫 번째는 Github 리포지토리의 Action 탭을 통하거나 두 번째는 로컬 리포지토리 자체에서 직접 하는 방법이 있습니다.&lt;br&gt;둘 다 괜찮지만 이 예제에서는 첫 번째 방법을 사용하여 Actions 인터페이스에 익숙해 질 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*kupfxiFhqcSTMno6pobMkQ.png&quot; alt=&quot;action&quot;&gt;&lt;/p&gt;
&lt;p&gt;처음 클릭하면 기본 제공되는 기본 구성을 제공하는 &amp;#39;시작&amp;#39; 페이지가 표시됩니다.&lt;br&gt;이를 건너 뛰고 워크 플로 설정을 직접 클릭 (set up a workflow yourself) 하고 처음부터 시작할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*MK2E8Nc5zktBvnOM_Dfb1A.png&quot; alt=&quot;yml0&quot;&gt;&lt;/p&gt;
&lt;p&gt;다음으로 Github의 코드 편집기에서 워크 플로를 수동으로 편집하고 변경 사항을 커밋 할 수 있습니다.&lt;br&gt;구문은 YAML이라는 언어이며 매우 일반적인 구성 도구입니다.&lt;br&gt;거의 모든 CI / CD 플랫폼은 구성 파일에서 이를 사용합니다.&lt;br&gt;당신이 전에 그것을 보지 못했다면, 픽업하기가 매우 쉽습니다.&lt;br&gt;가장 먼저 할 일은 파일 production.yml의 이름을 바꾸고 커밋 시작을 클릭하여 변경 사항을 저장합니다.&lt;/p&gt;
&lt;h2&gt;배포하기 :&lt;/h2&gt;
&lt;p&gt;이제 로컬 리포지토리로 다시 이동하여 새 작업 워크 플로 파일이 포함 된 최신 변경 사항을 가져올 수 있습니다.&lt;br&gt;준비 및 프로덕션 환경에 배포 할 파일을 추가 할 위치입니다.&lt;br&gt;편집기를 연 상태에서 name프로덕션 빌드로 변경하고 브랜치에 푸시 할 때와 풀 요청이 열릴 때 트리거 하는 키를 변경하십시오.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: Production Build
on:
  pull_request:
  push:
    branches:
      - master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러면 특정 푸시가 발생할 때마다 해당 파일과 아래에 설명 된 단계가 트리거됩니다.&lt;br&gt;트리거하려는 항목에 따라 동일하거나 다른 분기를 수신하는 파일을 원하는 만큼 설정할 수 있습니다.&lt;br&gt;다음 단계는 jobs푸시 후에 수행 할 기능을 추가해야하는 단계입니다 .&lt;br&gt;아래에서 볼 수 있듯이 build 작업이 이미 존재하므로 runs-on단계 와 함께 유지할 수 있습니다 .&lt;br&gt;여기에서는 앱을 실행할 가상 인스턴스에 대해 간략하게 설명하고 이 예제에서는 기본값을 유지합니다.&lt;br&gt;그러나 strategyand matrix키를 사용하여 실행하려는 Node 버전을 추가해야 합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: Production Build
on:
  pull_request:
  push:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [8.x, 10.x, 12.x]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;지금까지는 아무 것도 트리거하지 않고 머신 및 노드 버전을 지정하기 만했습니다.&lt;br&gt;8.x, 10.x 및 12.x 용 노드 버전이 포함되어 있음을 알 수 있습니다.&lt;br&gt;이 버전은 필요하지 않지만 앱이 이러한 각 버전에서 작동하도록 합니다.&lt;br&gt;원하는대로 제거하거나 더 추가 할 수 있습니다.&lt;br&gt;이제 앱 배포에 필요한 단계로 넘어갈 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: Production Build
on:
  pull_request:
  push:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [8.x, 10.x, 12.x]

    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이제steps 에 키를 사용하여 워크 플로가 진행되는 단계를 간략하게 설명 할 수 있습니다.&lt;br&gt;첫 번째는 &lt;code&gt;actions/checkout&lt;/code&gt; Github Action을 실행하는 것 입니다.&lt;br&gt;이 조치는 &lt;strong&gt;$GITHUB_WORKSPACE&lt;/strong&gt; 아래에서 저장소를 체크 아웃 하므로 워크 플로우가 액세스 할 수 있습니다.&lt;br&gt;기본적으로 워크 플로우를 트리거 한 저장소는 체크 아웃됩니다.&lt;br&gt;체크아웃과 함께 &lt;code&gt;actions/setup-node&lt;/code&gt; 가 실행되며, 이는 전략 단계 중 매트릭스에서 정의한 노드 버전을 사용하여 환경에 대한 노드를 설정합니다.&lt;br&gt;보시다시피 이 작업은 ${{ matrix.node 버전}}을 참조하며 매트릭스 어레이에 정의된 노드 버전만큼 많은 버전으로 실행됩니다.&lt;br&gt;이제 S3에 배포하기 전에 앱을 설치, 빌드 및 테스트 할 수 있습니다.&lt;br&gt;이것은 매우 간단하며 다른 앱의 CI / CD 구성을 작성한 경우 이를 인식합니다.&lt;br&gt;이 경우 Yarn을 create-react-app의 기본 패키지 관리자로 사용합니다.&lt;br&gt;그러나 이것은 NPM 및 기타와 동일하게 작동합니다.&lt;br&gt;이 Yarn 스크립트를 실행하면 앱이 올바르게 빌드되고 S3 버킷으로 푸시되기 전에 모든 단위 테스트를 통과하지만 린트와 같은 것을 이 단계에서 더 많은 단계를 추가 할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: Production Build
on:
  pull_request:
  push:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [8.x, 10.x, 12.x]

    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - name: Yarn Install
        run: |
          yarn install
      - name: Production Build
        run: |
          yarn build
      - name: Unit Tests
        run: |
          yarn test&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마지막으로, 우리는 Github 액션 s3-sync-action by Jake Jarvis 에서 호출을 사용하여 이루어질 수 있는 배치 단계에 추가할 필요가 있습니다.&lt;br&gt;Action은 컴파일 된 애플리케이션을 가져와 미리 정의 된 환경 변수를 사용하여 지정된 S3 버킷으로 보냅니다 (나중에 자세히 설명).&lt;br&gt;uses 키를 다시 한 번 사용하면 동작을 가져 오기 위해 수행해야 할 모든 것입니다.&lt;br&gt;그런 다음 with키를 사용하여 S3에 업로드 할 때 필요한 관련 인수를 활용합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;--acl public-read: 당신의 S3버캇이 공개적으로 읽을 수 있도록 구성되어 있다고 가정할 경우 이는 사람이 올린 파일이 있도록 보장할 것입니다.&lt;/li&gt;
&lt;li&gt;--delete: 이것은 올린 파일에 없는 S3버킷이 안에 있는 파일을 삭제합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;우리의 최종 배포 스크립트:&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: Production Build
on:
  pull_request:
  push:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [8.x, 10.x, 12.x]

    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - name: Yarn Install
        run: |
          yarn install
      - name: Production Build
        run: |
          yarn build
      - name: Unit Tests
        run: |
          yarn test
      - name: Deploy to S3
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --acl public-read --delete
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_PRODUCTION_BUCKET_NAME }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: ${{ secrets.AWS_REGION }}
          SOURCE_DIR: &amp;quot;build&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;환경 변수:&lt;/h2&gt;
&lt;p&gt;현재 워크 플로우는 명시 적으로 설정되지 않은&lt;br&gt;AWS_S3_BUCKET,&lt;br&gt;AWS_ACCESS_KEY_ID,&lt;br&gt;AWS_SECRET_ACCESS_KEY 또는&lt;br&gt;AWS_REGIONS3 에 업로드하는 데 필요한 변수를 설정해야 합니다.&lt;br&gt;이러한 코드가 코드 내에 노출되지 않도록 하기 위해 각 리포지토리의 설정 메뉴를 통해 추가하고 액세스 할 수 있습니다.&lt;br&gt;설정을 클릭 한 다음 secret 옵션을 선택하면이 페이지가 나타납니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*ygL1a2MxVe3EPZ2dB-xXeA.png&quot; alt=&quot;secret&quot;&gt;&lt;/p&gt;
&lt;p&gt;보시다시피 API 키 또는 자격 증명과 같은 많은 비밀 변수를 공개하지 않고 추가 할 수 있습니다.&lt;br&gt;새 비밀 추가를 클릭 하고 비밀 키와 해당 값을 입력하면 됩니다.&lt;br&gt;이 안내서를 확인하지 않으면 프로덕션 및 스테이징 환경에 대해 AWS로 S3 버킷을 이미 설정했다고 가정합니다.&lt;br&gt;준비가 되면 이 안내서 에 따라 AWS 키와 ID를 검색 할 수 있습니다.&lt;br&gt;이제 React 앱을 설정하고, 프로덕션 환경의 워크 플로우를 완료하고, S3 버킷을 설정하고, 환경 비밀을 Github에 추가해야 합니다.&lt;br&gt;이제 변경 사항을 적용하고 첫 번째 CI / CD 배포를 시작할 수 있습니다.&lt;br&gt;master 워크 플로우를 시작하려면 지점에서 수행해야 합니다 .&lt;br&gt;Github과 repo의 Actions 탭으로 가면 빌드 및 배포가 실행되고있는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1400/1*AK1OaPbfe4m4kZHGCUQOmQ.png&quot; alt=&quot;ready&quot;&gt;&lt;/p&gt;
&lt;h2&gt;워크 플로우 준비 :&lt;/h2&gt;
&lt;p&gt;마지막으로해야 할 일은 준비 환경에 대한 프로덕션 워크 플로를 복제하는 것입니다.&lt;br&gt;기본적으로 이 인스턴스에 대해 다른 S3 버킷을 설정하지 않았다면 아직 Github의 다른 환경 비밀에 준비 버킷 이름(AWS_STAGING_BUCKET_NAME)을 추가해야 합니다.&lt;br&gt;이 작업이 완료되면, 우리는 workflows 폴더에 새로운 staging.yml 파일을 생성 할 수 있습니다.&lt;br&gt;이제 작업이 커밋되고 staging 지점으로 푸시 된 경우에만이 워크 플로가 실행되도록 약간의 변경 작업을 수행할 준비가 되었습니다.&lt;/p&gt;
&lt;p&gt;이 파일의 주요 변경 사항은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;워크 플로우의 이름을 Staging Build&lt;/li&gt;
&lt;li&gt;준비 환경으로 끌어 오기 요청을 할 가능성이 거의 없으므로 on 섹션에서 pull_request 를 제거하십시오.&lt;/li&gt;
&lt;li&gt;변경 master에 branches 에 staging&lt;/li&gt;
&lt;li&gt;Production Build단계 이름을 다음으로 변경하십시오. Staging Build&lt;/li&gt;
&lt;li&gt;AWS_S3_BUCKET 환경 변수를 다음으로 변경하십시오.${{ secrets.AWS_STAGING_BUCKET_NAME }}&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: Staging Build
on:
  push:
    branches:
      - staging
jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [8.x, 10.x, 12.x]

    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - name: Yarn Install
        run: |
          yarn install
      - name: Staging Build
        run: |
          yarn build
      - name: Unit Tests
        run: |
          yarn test
      - name: Deploy to S3
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --acl public-read --delete
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_STAGING_BUCKET_NAME }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: ${{ secrets.AWS_REGION }}
          SOURCE_DIR: &amp;quot;build&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이러한 변경 사항이 저장되고 staging지점으로 푸시되면 Github 리포지토리의 작업 탭에서 동일한 워크 플로가 실행됩니다.&lt;br&gt;그런 다음 각 프로덕션 및 준비 URL로 이동하여 새로 배포 된 React 앱이 현재 활성화되어 있는지 확인할 수 있습니다.&lt;/p&gt;</description>
      <category>Be well coding/Learn more</category>
      <author>be well</author>
      <guid isPermaLink="true">https://analogcoding.tistory.com/189</guid>
      <comments>https://analogcoding.tistory.com/189#entry189comment</comments>
      <pubDate>Wed, 22 Apr 2020 14:01:01 +0900</pubDate>
    </item>
  </channel>
</rss>