티스토리 뷰

Part 1. 시작하며

01. 무엇을 배울 것인가

intex.html
->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2.2 객체 to DOM Render</title>
  <script type="module" src="app.js"></script>
</head>
<body>
 <div id="root"></div>
 
</body>
</html>


app.js
->
function createDOM(node) {
  if(typeof node === 'string') {
    return document.createTextNode(node);
  }
  const element = document.createElement(node.tag);

  node.children
    .map(createDOM)
    .forEach(element.appendChild.bind(element));

  return element;
}



const vdom = {
  tag:'p',
  props:{}, //객체요소
  children: [
    {
      tag:'h1',
      props:{}, //객체요소
      children:["React 만들기"], //문자열
    },
    {
      tag: 'ul',
      props: {},
      children: [
        {
          tag: 'uli',
          props: {},
          children: ["첫 번째 아이템"]
        },
        {
          tag: 'uli',
          props: {},
          children: ["두 번째 아이템"]
        },
        {
          tag: 'uli',
          props: {},
          children: ["세 번째 아이템"]
        }
      ]
    }
  ],//자식요소
};

document
.querySelector('#root')
.appendChild(createDOM(vdom)); 

02. 1타 2피, 3피, 4피

*참고 사이트: https://caniuse.com/

-> 검색 async 

DOM 의 문제를 개선시키기 위한 react.js 입니다.
DOM 자체를 사용하지 않는다.

03. 작게 시작하기

*참고 사이트: https://ko.wikipedia.org/wiki/%EC%B5%9C%EC%86%8C_%EA%B8%B0%EB%8A%A5_%EC%A0%9C%ED%92%88

Rreact : 초기엔 'JavaScript Iibrary' 를 가지고 있었다.

Declarative(선언적) : 선언적인 '코드'가 생산되게끔 유도하는게 'React'의 대표 커셈 중 하나
Efficient(효율적인) :  'React'는 'DOM'과 'interaction' 하는 것을 최소화 한다. 그리고 'DOM'에 모의 표현을 사용하여 'DOM'을 처리한다
Flexible(유연성) : 우리가 이미 알고 있는 'library'와 혹은 'Framework'과 같은 것들과같이 동작할 수 있다. 그래서 유연성이 높다.

04. 변경하지 않고 확대하기

*참고 사이트: https://ko.wikipedia.org/wiki/%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8

05. 웹프론트앤드 개발환경

*참고 사이트: 

https://webpack.kr/

https://babeljs.io/


Part 2. React 만들기

01. 해결책 만들기

02. 객체 to DOM Render

html
->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2.2 객체 to DOM Render</title>
  
</head>
<body>
 <div id="root"></div>
 <script src="app.js" type="module"  defer></script>
</body>
</html>

app.js
->

function createDOM(node) {
  if(typeof node === 'string') {
    return document.createTextNode(node);
  }

  const element = document.createElement(node.tag);

  node.children
    .map(createDOM)
    .forEach(element.appendChild.bind(element));

  return element;
}



const vdom = {
  tag:'p',
  props:{}, //객체요소
  children: [
    {
      tag:'h1',
      props:{}, //객체요소
      children:["React 만들기"], //문자열
    },
    {
      tag: 'ul',
      props: {},
      children: [
        {
          tag: 'li',
          props: {},
          children: ["첫 번째 아이템"]
        },
        {
          tag: 'li',
          props: {},
          children: ["두 번째 아이템"]
        },
        {
          tag: 'li',
          props: {},
          children: ["세 번째 아이템"]
        },
      ]
    }
  ],//자식요소
};

document
.querySelector('#root')
.appendChild(createDOM(vdom)); 

--> 화면이 나오지 않아 오류 확인중...

03. webpack 과 babel 세팅

터미널을 키고
npm init -y

개발환경 설정하기
npm install webpack-cli --save-dev 

npm install webpack-dev-server babel-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin --save-dev


다음 webpack.config.js 파일을 만든다.(node.js)

html
->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2.3 setup webpack & babel</title>
  
</head>
<body>
 <div id="root"></div>
 <script src="app.js" type="module"  defer></script>
</body>
</html>

app.js
->
const HtmlWbpackPlugin =  require('html-webpack-plugin');
const path= require('path');

module.exports = {
    mode: 'development', //객체 입력정보(어떤 자바스크립트의 정보를 입력할지)
    entry: './app.js', //키
    output: { //출력
        path: path.resolve(__dirname,'dist'),
        filname: 'bundle.js'
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/, //정규식으로 패턴화  
                use: {
                    loader:'babel-loader',
                }
                options: {
                    presets:["@babel/preset-env", "@babel/preset-react"]
                }
            }
        ]
    },

    plugins: [
        new HtmlWbpackPlugin({
            title: '2.3 setup webpack & babel',
            template: 'index.html'
        })
    ]
}

//기본적인 세팅

*참고사이트: https://www.npmjs.com/

검색: html-webpack-plugin


파일 생성 bable.config.json


package.json에 추가

  "scripts": {
    "webpack": "webpack",
    "dev": "webpack serve",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

터미널에서 npm run dev 실행 확인 하기

-->>실행이 안됨;; 뭔지 모르겠지만

html
->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2.3 setup webpack & babel</title>
  
</head>
<body>
 <div id="root"></div>

</body>
</html>
app.js / react.js 폴더 나누기
app.js (상위폴더 src 안으로 넣기)
->
import { createDOM, render } from "./react";
const vdom = {
  tag:'p',
  props:{}, //객체요소
  children: [
    {
      tag:'h1',
      props:{}, //객체요소
      children:["React 만들기"], //문자열
    },
    {
      tag: 'ul',
      props: {},
      children: [
        {
          tag: 'li',
          props: {
            style: "color:red",
          },
          children: ["첫 번째 아이템"]
        },
        {
          tag: 'li',
          props: {
            style: "color:blue",
          },
          children: ["두 번째 아이템"]
        },
        {
          tag: 'li',
          props: {
            style: "color:green",
          },
          children: ["세 번째 아이템"]
        },
      ]
    }
  ],//자식요소
};

render(vdom, document.querySelector('#root'));


react.js (상위폴더 src 안으로 넣기) 
->

export function createDOM(node) {
    if(typeof node === 'string') {
      return document.createTextNode(node);
    }
  
    const element = document.createElement(node.tag);
    
    Object.entries(node.props)
        .forEach(([name, value]) => element.setAttribute(name, value));

    node.children
      .map(createDOM)
      .forEach(element.appendChild.bind(element));
  
    return element;
  }
  
  export function render(vdom, container) {
    container.appendChild(createDOM(vdom));
  }


04. create Element

app.js
->
import { createDOM, createElement,render } from "./react";

const vdom = createElement('p', {},
  createElement('h1', {}, "React 만들기"),
  createElement('ul', {},
    createElement('li', { style: "color:red", "첫 번째 아이템"}),
    createElement('li', { style: "color:blue", "첫 번째 아이템"}),
    createElement('li', { style: "color:green", "첫 번째 아이템"}),
  )
);

console.log(vdom);

render(vdom, document.querySelector('#root'));

05. @jsx

app.js
->
import { createDOM, createElement,render } from "./react";

const vdom = <p>
  <h1>React 만들기</h1>
  <ul>
    <li style="color:red">첫번째 아이템</li>
    <li style="color:blue">두번째 아이템</li>
    <li style="color:green">세번째 아이템</li>
  </ul>
</p>

console.log(vdom);

render(vdom, document.querySelector('#root'));

react.js
->

export function createDOM(node) {
    if(typeof node === 'string') {
      return document.createTextNode(node);
    }
  
    const element = document.createElement(node.tag);
    
    Object.entries(node.props)
        .forEach(([name, value]) => element.setAttribute(name, value));

    node.children
      .map(createDOM)
      .forEach(element.appendChild.bind(element));
  
    return element;
  }
  
  export function createElement(tag, props, ...children) {
    return {tag, props, children};
  }
  
  export function render(vdom, container) {
    container.appendChild(createDOM(vdom));
  }

06. 함수 컴포넌트

app.js
->
import { createDOM, createElement,render } from "./react";

function Title(props) {
  console.log('여기는 타이틀');
  return <h1>{ props.children }</h1>;
}

function Item(props) {
  return <li style={`color:${props.color}`}>{props.children}</li>
}


const vdom = <p>
  <Title label="React">React 정말 잘 만들기</Title>
  <h1>React 만들기</h1>
  <ul>
    <Item style="color:red">첫번째 아이템</Item>
    <Item style="color:blue">두번째 아이템</Item>
    <Item style="color:green">세번째 아이템</Item>
  </ul>
</p>

console.log(vdom);

render(vdom, document.querySelector('#root'));


react.js
->

export function createDOM(node) {
    if(typeof node === 'string') {
      return document.createTextNode(node);
    }
  
    const element = document.createElement(node.tag);
    
    Object.entries(node.props)
        .forEach(([name, value]) => element.setAttribute(name, value));

    node.children
      .map(createDOM)
      .forEach(element.appendChild.bind(element));
  
    return element;
  }
  
  export function createElement(tag, props, ...children) {
    props = props || {};

    if(typeof tag === 'function') {
        if(children.length > 0){
            return tag({
                ...props,
                children: children.length === 1 ? children[0] : children,
            })
        } else{
            return tag(props);
        }
    } else {
        return { tag, props, children };
    }
    
  }

  export function render(vdom, container) {
    container.appendChild(createDOM(vdom));
  }

07. 클래스 컴포넌트

app.js
->
import { createElement, render, Component } from "./react";

function Title extends Component {
  render(){
    return <h1>{ props.children }</h1>;
  }
}

function Item(props) {
  return <li style={`color:${props.color}`}>{props.children}</li>
}

const vdom = <p>
  <Title label="React">React 정말 잘 만들기</Title>
  <h1>React 만들기</h1>
  <ul>
    <Item style="color:red">첫번째 아이템</Item>
    <Item style="color:blue">두번째 아이템</Item>
    <Item style="color:green">세번째 아이템</Item>
  </ul>
</p>

console.log(vdom);

render(<App/ >vdom, document.querySelector('#root'));


react.js
->

export function createDOM(node) {
    if(typeof node === 'string') {
      return document.createTextNode(node);
    }
  
    const element = document.createElement(node.tag);
    
    Object.entries(node.props)
        .forEach(([name, value]) => element.setAttribute(name, value));

    node.children
      .map(createDOM)
      .forEach(element.appendChild.bind(element));
  
    return element;
  }
  
  export function createElement(tag, props, ...children) {
    props = props || {};

    if(typeof tag === 'function') {
        if (tag.prototype instanceof Component){
            const instance = new tag(makeProps(props, children));
            return instance.render();
        }
        if(children.length > 0){
            return tag({
                ...props,
                children: children.length === 1 ? children[0] : children,
            })
        } else{
            return tag(props);
        }
    } else {
        return { tag, props, children };
    }
    
  }

  export function render(vdom, container) {
    container.appendChild(createDOM(vdom));
  }

08. virtual DOM

*참조사이트: https://awesomeopensource.com/projects/virtual-dom

app.js
->
import { createElement, ,render, Component } from "./react";

function Title extends Component {
  render(){
    return <h1>{ props.children }</h1>;
  }
}

function Item(props) {
  return <li style={`color:${props.color}`}>{props.children}</li>
}

const vdom = <p>
  <Title label="React">React 정말 잘 만들기</Title>
  <h1>React 만들기</h1>
  <ul>
    <Item style="color:red">첫번째 아이템</Item>
    <Item style="color:blue">두번째 아이템</Item>
    <Item style="color:green">세번째 아이템</Item>
  </ul>
</p>

render(<App/ >vdom, document.querySelector('#root'));


react.js
->
export  class Component {
    constructor(props) {
        this.props = props;
    }
}

export function createDOM(node) {
    if(typeof node === 'string' || typeof node === 'number') {
      return document.createTextNode(node);
    }
  
    const element = document.createElement(node.tag);
    
    node.props && Object
        .entrieds(node.props)
        .forEach(([name, value]) => element.setAttribute(name, value));

    node.children && node.children
      .map(createDOM)
      .forEach(element.appendChild.bind(element));
  
    return element;
  }

  function makeProps(props, children){
    return {
        ...props,
        children: children.length === 1 ? children[0] : children
    }
  }
  
  export function createElement(tag, props, ...children) {
    props = props || {};

    if(typeof tag === 'function') {
        if (tag.prototype instanceof Component){
            const instance = new tag(makeProps(props, children));
            return instance.render();
        }
        if(children.length > 0){
            return tag({
                ...props,
                children: children.length === 1 ? children[0] : children,
            })
        } else{
            return tag(props);
        }
    } else {
        return { tag, props, children };
    }
  }

  export function render(vdom, container) {
    container.appendChild(createDOM(vdom));
  }

  export const render = (function() {
    let prevDom = null;

    return function(vdom, container) {
        if(prevDom === null) {
            prevDom = vdom;
        }

        container.appendChild(createDOM(vdom));
    }
  })();


09. 마법의 Hook 원리와 제약

*참조사이트: https://reactjs.org/docs/hooks-faq.html#gatsby-focus-wrapper (react 공식 홈페이지)

react.js
->
export  class Component {
    constructor(props) {
        this.props = props;
    }
}

export function createDOM(node) {
    if(typeof node === 'string' || typeof node === 'number') {
      return document.createTextNode(node);
    }
  
    const element = document.createElement(node.tag);
    
    node.props && Object
        .entrieds(node.props)
        .forEach(([name, value]) => element.setAttribute(name, value));

    node.children && node.children
      .map(createDOM)
      .forEach(element.appendChild.bind(element));
  
    return element;
  }

  function makeProps(props, children){
    return {
        ...props,
        children: children.length === 1 ? children[0] : children
    }
  }
  
  function useState(initValue) {
    if (!hook[currentComponent]) {
        hooks[currentComponent] = initValue;
    }

    const modifier = nextValue => {
        hooks[currentComponent] = nextValue;
    };

    return[ hooks[position], modifier ];
  }

  export function createElement(tag, props, ...children) {
    if(typeof tag === 'function') {
        if (tag.prototype instanceof Component){
            const instance = new tag(makeProps(props, children));
            return instance.render();
        }
        
        hooks[currentComponent] =  null;
        currentComponent++;

        if (children.length > 0) {
            return tag(makeProps(props, children));
        } else {
            return tag(props);
        }
    }
        return { tag, props, children };
    }
  

  export function render(vdom, container) {
    container.appendChild(createDOM(vdom));
  }

  export const render = (function() {
    let prevDom = null;

    return function(vdom, container) {
        if(prevDom === null) {
            prevDom = vdom;
        }

        container.appendChild(createDOM(vdom));
    }
  })();

10. 사이드 이펙트

실제로 'DOM'의 문제를 해결하기 위해서 제안했던 방법이 나름의 사이드 이펙트로 장점으로 승화되는 측면들이 많다.
그 승화되는 측면들이 '프론트엔드' 업계에 굉장히 많은 기술적인 진보를 가져왔다.
ex) virtual DOM

댓글
© 2018 eh2world