1. props로 하위 콤포넌트에 전달 

useState는 상태 값과 그 값을 갱신하는 함수를 반환합니다.

const [state, setState] = useState(initialState);
setState(newState);

다음은 간단한 useState를 사용하고 props를 통해서 하위 콤퍼넌트로 전달하여 화면에 노출하는 코드입니다.

import React, { useState } from 'react';

const Welcome = (props) => {
  return (
    <>
    <h1>Hello, {props.name}</h1>
    </>
  )
}

const App = () => {
  //상태값
  const [age, setAge] = useState(42);
  return (
    <div className="App">
      <header className="App-header">
        <Welcome name={age}/>
      </header>
    </div>
  )
}

useState를 이용해서 [age, setAge] state 변수 age와 state를 갱신할 수 있는 setAge함수가 만들어지고 

setAge로 값을 설정하면 값이 갱신이되고 컴포넌트를 리 렌더링되게 됩니다.

 

하위 콤포넌트에서 해당 상태값을 참조하기 위해서는 props를 통해서 인자로 넘겨야 해서

상태값이 많거나 하위 component 복잡도가 높아질수록 관리의 어려움이 있습니다.

useContext를 통해서 전달 하도록 개선합니다.

 

2. useContext를 이용하여 global state 

context는 React 컴포넌트 트리 안에서 전역적(global)이라고 볼 수 있는 데이터를 공유할 수 있도록 고안된 방법입니다. 그러한 데이터로는 현재 로그인한 유저, 테마, 선호하는 언어 등이 있습니다.

 

사용방법은 상위 콤포넌트에서 Context를 생성해서 Context.Provider 로 값을 하위로 전달을 하면

하위 컴포넌트에서 필요시 구독하여 값을 사용할 수 있습니다.

 

1. React.createConntext(initialState) 로 Context생성

2. 상위 콤포넌트에서 Context.Provider value로 전달 

3. 하위 콤포넌트에서 useContext를 이용해서 참조 

...
const initialState = {
  index: 0
}
const Reducer = (state, action) => {
  console.log("action : " + action);
  switch (action.type) {
    case 'plus': {
      return { index: state.index + action.value}
    }
    default: {
      return state
    }
  }
}
...


//상위 컴포넌트
export const Context = React.createContext(initialState);
function App() {
  const [state, dispatch] = useReducer(Reducer, initialState)

  return (
    //하위로 value 전달
    <Context.Provider value={{state, dispatch}}>
       <Main />
       <Body />
    </Context.Provider>
  );
}

//하위 콤포넌트 사용하기 
...
//useContext를 이용하여 값을 가져와 사용
const {state, dispatch} = useContext(Context);
...
return (
     {state.index}
)

 

3.전체 소스

프로젝트 생성후 실행 

npx create-react-app my-app
npm start

 

App.js

import React, {useReducer} from 'react';
import Main from "./components/Main";
import Body from "./components/Body";
import './App.css';


const initialState = {
  index: 0
}

const Reducer = (state, action) => {
  console.log("action : " + action);
  switch (action.type) {
    case 'plus': {
      return { index: state.index + action.value}
    }
    default: {
      return state
    }
  }
}

export const Context = React.createContext(initialState);
function App() {
  const [state, dispatch] = useReducer(Reducer, initialState)

  return (
    <Context.Provider value={{state, dispatch}}>
       <Main />
       <Body />
    </Context.Provider>
  );
}

export default App;
import React, {useReducer} from 'react';
import Main from "./components/Main";
import Body from "./components/Body";
import './App.css';


const initialState = {
  index: 0
}

const Reducer = (state, action) => {
  console.log("action : " + action);
  switch (action.type) {
    case 'plus': {
      return { index: state.index + action.value}
    }
    default: {
      return state
    }
  }
}

export const Context = React.createContext(initialState);
function App() {
  const [state, dispatch] = useReducer(Reducer, initialState)

  return (
    <Context.Provider value={{state, dispatch}}>
       <Main />
       <Body />
    </Context.Provider>
  );
}

export default App;

 

Main.js

import React, {useContext, useState, useReducer} from 'react';
import {Context}  from "../App.js";

const Main = () => {
    const {state, dispatch} = useContext(Context);
    return (
      <div className="Main">
      main
      <header className="App-header">
        <p>
        {state.index}
        </p>
        <li
          onClick={()=>{ dispatch({ type: 'plus', value: 1 }) }}
        >
          Plus
        </li>
      </header>
    </div>
    )
}

export default Main;

 

Body.js

import React, {useContext, useState, useReducer} from 'react';
import {Context}  from "../App.js";
const BodyField = (props) => {
  return (
    <>
    <h1>{props.name}</h1>
    </>
  )
}

const Body = () => {
  //값전달
  const {state, dispatch} = useContext(Context);
  return (
    <div className="Body">
      body
      <header className="App-header">
        <BodyField name={state.index}/>
      </header>
    </div>
  )
}

export default Body;

 

결과

App에서 Main과 Body콤포넌트를 가지고 있고 하위 콤포넌트에서 index값을 참조 plus를 클릭시 동시에 갱신이 되는 

간단한 소스를 확인해보았고 Context를 통해서 하위콤포넌트에서 상태값을 공유하는 방법을 사용해 보았습니다.

 

 

 

자세한 내용은 하기 URL에서 확인 할 수 있습니다.

ko.reactjs.org/docs/getting-started.htmlko.reactjs.org/docs/hooks-reference.html#usecontext

 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

프로미스에 대해서 사용해보겠습니다. 

자세한 설명은 하기 URL을 참고 하시기 바랍니다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

프로미스는 비동기 작업에 대해서 완료 또는 실패를 결과를 콜백을 전달하는 대신, 콜백을 첨부하는 방식의 객체입니다.

 

Promise

기본동작 예제  

  1. asyn를 원하는 작업에 대해서 Promise로 감싸고 파라미터로 전달된 resolve or reject로 성공 실패를 호출합니다.

  2. 결과를 return을 받으면 then, catch구문을 이용하여 결과, 에러에 대해서 처리를 할 수 있습니다.  

Promise를 여러게 처리하기 위해서  

하기와 같이 Promise.All을 이용하여 처리를 할 수 있습니다.

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});


Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

 

Promise 흐름은 다음과 같습니다.

 

async / await 비동기처리

또다른 방법으로 async / await를 사용할 수 있습니다.

async function 선언은 AsyncFunction객체를 반환하는 하나의 비동기 함수를 정의합니다

 

기본 동작 

기존에 만들어 놓은 asyncFunction을 호출 

async function asyncCall() {
    console.log('calling’);
    try {
        const result = await asyncFunction();
        console.log("asyncCall : " + result);
    } catch(err) {
        //error 
        console.log(“error : " + err);
    }
    // expected output: "resolved"
}

내부적으로 async 함수는 항상 promise를 반환합니다. 만약 async 함수의 반환값이 명시적으로 promise가 아니라면 암묵적으로 promise로 감싸집니다.

 

async function foo() {
    return 1
}

위 코드는 아래와 같습니다.
function foo() {
    return Promise.resolve(1)
}
async function foo() {
    await 1
}

위 코드는 아래와 같습니다.
function foo() {
    return Promise.resolve(1).then(() => undefined)
}

위와 같이 비동기 처리에 대해서 사용해 보았습니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function deepCopy(array) {
    return JSON.parse(JSON.stringify(array));
}
 
var ascArr = [];
ascArr.push({'id':'id1''step':'1'});
ascArr.push({'id':'id2''step':'5'});
ascArr.push({'id':'id3''step':'2'});
ascArr.push({'id':'id4''step':'3'});
ascArr.push({'id':'id5''step':'2'});
ascArr.push({'id':'id6''step':'4'});
ascArr.push({'id':'id7''step':'1'});
 
// 오름차순
//compareFunction(a, b)이 0보다 작은 경우 a를 b보다 낮은 색인으로 정렬합니다. 즉, a가 먼저옵니다.
ascArr.sort(function(a, b) { 
    return a.step - b.step;
});
 
var descArr = deepCopy(ascArr);
// 내림차순
//compareFunction(a, b)이 0보다 큰 경우, b를 a보다 낮은 인덱스로 소트합니다.
descArr.sort(function(a, b) { 
    return b.step - a.step;
});
 
 
cs

HTML에서 Table을 세로값이 같으면 cell merge가 되어야 보기좋게 표현할 수 있습니다.
그려진 table에 대해서 동적으로 값을 비교하면서 Rowspan을
계산하여 적용하는 함수입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function dynamicRowSpan() {
    var table = document.getElementById("table");
    var trArr = table.getElementsByTagName("tr");
    var thCnt = table.rows[0].getElementsByTagName("th").length;
    
    for (var tdIdx = thCnt-1; tdIdx >= 0; tdIdx--) {
        var rowSpan = 0;
        var compText = '';
        for (var trIdx = 1; trIdx < trArr.length; trIdx++) {
            var td = table.rows[trIdx].cells[tdIdx]; 
            if (compText == '') {
                compText = td.outerText;
                continue;
            }
            if (compText == td.outerText) {
                rowSpan++;
                td.setAttribute("class""del");
            } else {
                var td = table.rows[trIdx-1-rowSpan].cells[tdIdx];
                td.setAttribute("rowspan", rowSpan+1);
                rowSpan = 0;
                compText = table.rows[trIdx].cells[tdIdx].outerText;
            }
 
            if ( trIdx == trArr.length-1 && rowSpan > 0 ) {
                var cell = table.rows[trIdx-rowSpan].cells[tdIdx];
                cell.setAttribute("rowspan", rowSpan+1);
                rowSpan = 0;
                compText = '';
            }
        }
    }
 
    table = document.getElementById("table");
    var dels = table.getElementsByClassName("del");
    for(var i = dels.length-1; i >= 0; i--){
        dels[i].remove();
    }
}
cs

+ Recent posts