반응형

반응형
반응형

https://codesandbox.io/s/explorer-l44v98?file=/index.js

 

Explorer - CodeSandbox

Explorer by fir0j using antd, react, react-dom, react-icons, react-scripts, styled-components

codesandbox.io

 

위 소스는 자식이 2개 이상 있으면 2개가 한꺼번에 오픈되는 에러 있음, 아래는 에러 수정한 버젼

import React, { Fragment, useEffect, useState } from "react";
import { IoMdArrowDropright } from "react-icons/io";
import { MdArrowDropDown } from "react-icons/md";
import styled from "styled-components";

const SelectParent = styled.div`
  padding: 7px 7px;
  background-color: darkblue;
  width: max-content;
  border-radius: 4px;
  margin-top: 4px;
  font-weight: bolder;
  color: white;
  cursor: pointer;
`;

const Selectname = styled.div`
  margin-top: 5px;
  padding: 7px 7px;
  width: fit-content;
  border-radius: 4px;
  cursor: default;
  color: darkblue;
  :hover {
    background-color: #bdbaba3c;
  }
`;

const Explorer = ({ parent = [], onParentClick, onNameClick /*expandOnHover = false*/ }) => {
  const [newData, setNewData] = useState([]);

  useEffect(() => {
    setNewData(parent.map((n) => ({ ...n, expand: false })));
  }, [parent]);

  const handleClickOnParent = (e, data) => {
    e.stopPropagation();
    if (onParentClick && onParentClick instanceof Function) onParentClick(data);

    const clickIdx = newData.findIndex((n) => data.name === n.name);
    const clickItem = newData.find((n) => data.name === n.name);

    setNewData([...newData.slice(0, clickIdx), { ...clickItem, expand: !clickItem.expand }, ...newData.slice(clickIdx + 1, newData.length)]);
  };

  const handleClickOnName = (e, data) => {
    e.stopPropagation();

    if (onNameClick && onNameClick instanceof Function) onNameClick(data);
  };

  return (
    <>
      {newData.map((item) => (
        <Fragment key={item.name}>
          {item.children && item.children.length ? (
            <Fragment /*key={index}*/>
              <SelectParent /*onMouseOver={() => (expandOnHover ? setExpand(true) : {})}*/ onClick={(e) => handleClickOnParent(e, item)}>
                {item.name} <span>{!item.expand ? <IoMdArrowDropright /> : <MdArrowDropDown />} </span>
              </SelectParent>

              {item.expand ? (
                <div style={{ paddingLeft: "1.5rem" }}>
                  <Explorer parent={item.children} onParentClick={onParentClick} onNameClick={onNameClick} /*expandOnHover={expandOnHover}*/ />
                </div>
              ) : null}
            </Fragment>
          ) : (
            <Selectname onClick={(e) => handleClickOnName(e, item)}>{item.name}</Selectname>
          )}
        </Fragment>
      ))}
    </>
  );
};

export default Explorer;
반응형
반응형

context 생성: import { createContext } from "react"

import { createContext } from "react";

// 기본값으로는 null을 넣어준다.
export const ThemeContext = createContext(null);

context 연결 <ThemeContext.Provider value={{ isDark, setIsDark }}>

import { useState } from "react";
import "./App.css";
import Page from "./Compopnents/Page";
import { ThemeContext } from "./context/ThemeContext";

function App() {
  const [isDark, setIsDark] = useState(false);

  return (
    // 📌
    <ThemeContext.Provider value={{ isDark, setIsDark }}>
      <Page />
    </ThemeContext.Provider>
  );
}
export default App;

 

context 사용 & 변경

  • import { useContext } from "react"
  • const { isDark, setIsDark } = useContext(ThemeContext);이때 setIsDark 콜하면 전체화면 refresh됨
import { useContext } from "react";
 // 📌 
import { ThemeContext } from "../context/ThemeContext";

const Header = () => {
  // 📌 
  const { isDark, setIsDark } = useContext(ThemeContext);////////////////////////
  return (
    <header
      className="header"
      style={{
        backgroundColor: isDark ? "black" : "lightgray",
        color: isDark ? "white" : "black",
      }}
    >
      <h1>Welcome 홍길동!</h1>
    </header>
  );
};

export default Header;

 

context를 가장 상위에서 불러와서 쓰기 때문에 전체 화면 refresh되는 것인지?

context를 state전용, dispatch전용으로 나누어써야 불필요한 렌더링 막을수 있다고 하는 예제https://velog.io/@shin6403/React-ContextAPI-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%8D%A8%EB%B3%B4%EC%9E%90

 

[React] ContextAPI 이렇게 써보자

어느날 구글링을 하다가 어떠한 글을 보았다.Context API는 왜 안쓰나요?ContextAPI를 쓰는 글쓴이에게 굉장히 관심이 가는 글이었고, 내용을 결론은 소규모 프로젝트에서는 ContextAPI가 좋지만 성능 때

velog.io

useReducer, useCallback, memo등을 같이 사용하고 있음

반응형
반응형

반응형
반응형

에러: Promise로 받은 state의 변화를 감지하려고 하여 useEffect사용했으나, Promise결과가 반환되기 전에 useEffect가 한번만 call되고 결과값이 나온후에 다시 call되지 않음

 
 const getDivisionList = async () => {
    try {return await request(getDivisions);}
    catch (error) {console.error(error);}
  };
 
 useEffect(() => {
    const init = async () => {
      const [divisions] = await Promise.all([getDivisionList()]);
     
      setDivisionOptionsValue(divisions.map(n=>({value:n.companyCode, label:n.companyCode, group:"sortType"})));
    };
    init();
  }, []);
 useEffect(() => {setDivisionOptions(setDivisionOptionsValue)}, [divisionOptionsValue]);
 ........
 divisionOptions[0].... -> 에러남

 

에러: promise결과값을 useMemo로 저장시 끝까지 promise상태고 남아 있어 에러남

  const divisionOptionsValue = React.useMemo(()=>{
    const init = async () => {
      const [divisions] = await Promise.all([getDivisionList()]);
      setDivisionOptions(divisions.map(n=>({value:n.companyCode, label:n.companyCode, group:"sortType"})));
      return (divisions.map(n=>({value:n.companyCode, label:n.companyCode, group:"sortType"})));
    };
    return init();
  },[])
 .......
 setDivisionOptions(setDivisionOptionsValue) -> setDivisionOptionsValue는 계속 Promise상태
 divisionOptions[0].... -> 에러남

 

정상

  useEffect(() => {
    const init = async () => {
      const [divisions] = await Promise.all([getDivisionList()]);
      setDivisionOptions(divisions.map(n=>({value:n.companyCode, label:n.companyCode, group:"sortType"})));
      setDivisionOptionsValue(divisions.map(n=>({value:n.companyCode, label:n.companyCode, group:"sortType"})));
    };
    init();
  }, []);
 
 .......
 setDivisionOptions(setDivisionOptionsValue)
divisionOptions[0].... -> 정상동작
반응형
반응형

https://simsimjae.tistory.com/382

 

왜 리액트는 대세가 되었을까?

주변에서 다들 리액트가 빠르다, 좋다. 하는데 정확히 어떤 부분이 좋은건데? 라고 물어보면 명확한 답변을 하기가 어려웠습니다. 그래서 이번기회에 리액트가 왜 좋은거고 어떤 장점이 있는건

simsimjae.tistory.com

 

브라우저의 렌더링 과정: parse -> layout -> paint -> composite(paint과정에서 나눠진 레이어들을 합침)

jQuery나 js로 직접 DOM에 접근해서 수정하면 매번 reflow (layout -> paint -> composite)이 일어나며 이는 렌더링 과정에서 대부분의 시간을 잡아먹는 작업이므로 비효율적

 

리액트는 업데이트가 필요한 UI컴포넌트를 하나씩 수정하지 않습니다. 리액트 컴포넌트가 리턴한 JSX를 해석해서 Virtual DOM에 그리고, 이것을 모든 컴포넌트에 대해서 반복합니다. 전부 다 그렸으면 실제 DOM과 비교해서 변경된 부분만 변경시켜주는것이죠. 어떻게 보면 조삼모사처럼 보일수도있습니다. 한번에 하나씩 변경시킬것인가? 아니면 모아서 한번에 처리할것인가? 근데 후자의 방법이 더 좋은 방법입니다. 왜냐면, 모아서 한번에 처리하면 리플로우는 딱 한번 일어나기 때문에 브라우저의 리소스를 덜 사용하기 때문입니다.

유저와의 상호작용이 많아서 서버에서 데이터를 가져와서 UI에 그 데이터를 묶어서 보여줘야 하는 경우가 많은 서비스에서는 리액트가 훨씬 개발하기 편하고 빠릅니다. 

DOM관리를 리액트가 알아서 편리하게 해주기 때문이죠. 저희는 그저 데이터와 UI 컴포넌트를 묶어주기만 하면 됩니다. 직접 DOM에 접근할 필요가 없어요.

출처: https://simsimjae.tistory.com/382 [104%:티스토리]

 

반응형
반응형

react node

<FormattedMessage> 사용하려면 IntlProvider를 윗단에서 아래와 같이 제공해줘야 함

import { IntlProvider } from "react-intl";
import enUsMsg from "./lang/en-US.json";
import koMsg from "./lang/ko.json";
import Page from "./Page";

const locale = localStorage.getItem("locale") ?? "ko";
const messages = { "en-US": enUsMsg, ko: koMsg }[locale];

function App() {
  return (
    <IntlProvider locale={locale} messages={messages}>
      <Page />
    </IntlProvider>
  );
}
import { FormattedMessage } from 'react-intl';

<FormattedMessage id={'user.table.tool.total'}/> //총 사용자 : {total}
<FormattedMessage id={'user.table.tool.total'} values={{total: 1000}}/> //총 사용자 : 1000, values는 넘겨주는 변수지정
<FormattedMessage id={'user.table.tool.total'} defaultMessage='notFound' /> //id에 해당하는 번역어 없을때, defaultMessage나옴 defaultMessage없으면 id가 나옴

ui에 나타날때  padding 위아래 10 차지함 

String

String으로 쓰려면 useIntl이나 ingetIntl로 intl객체를 props로 받아와서 intl.formatMessage({id:...}) 형태로 사용해야함

import {injectIntl} from "react-intl";

const title = intl.formatMessage({id: 'index.portal.title'});

export injectIntl(...);
반응형
반응형

react component에는 2가지 종류가 있다 - 클래스형, 함수형

  • 아래 예시에서 보다시피 클래스형은 함수형보다 코드 길이가 더 길고 복잡
  • 함수형은 클래스형보다 메모리 자원도 덜 차지한다고 함 (왜??)
  • 그렇지만 함수형은 별도의 state나 lifecycle 정의를 할 수 없었기 때문에 간단한 용도로만 사용되었으나,
  • 2019년 리액트 버젼16.8부터 추가된 hook으로 인해 함수형이 클래스형보다 많이 쓰이게 되었음
  • 클래스형은 안쓴지 오래되서 이제 어떻게 쓰는지도 잘 모르겠음 (클래스형 https://devowen.com/298 참고하자)

 

class component

class Classcomp extends React.Component {
    state = {...};
    render(){
    	return(
        	<div className="containter>...</div>
        );
    }
}

function component

function FunctionComp(props){

	return (<div>...</div>);

}
반응형
반응형
반응형

'react' 카테고리의 다른 글

react-intl (international, 다국어 관련)  (0) 2022.08.02
react component: class vs function  (0) 2022.05.26
react hook: 16.8부터 추가  (0) 2020.01.02
react에서 (re)hydration(수화,수분보충)의 의미  (0) 2019.12.18
Redux Study  (0) 2019.09.27
반응형
  • useState
  • useEffect
    • react component가 rendering될때마다 특정작업 수행하도록 설정
    • componentDidMount + componentDidUpdate
      • 화면에 처음 렌더링될 때만(마운트될때만) 실행: useEffect(  ()=>{실행할일}, []  );
      • 특정값이 업데이트될때만 실행: useEffect(  ()=>{실행할일}, [name]  );
  • useContext
  • useReducer
  • useMemo
    • 불필요한 연산 반복하지 않도록 연산을 최적화
    • 매번 렌더링할 때마다 연산하지 않고 특정값이 바꼈을때만 연산하도록 지정
  • useCallback
    • useMemo와 비슷
    • 함수를 반환하는 상황에서 더 편하게 사용가능
  • useRef

https://velog.io/@velopert/react-hooks

 

반응형

'react' 카테고리의 다른 글

react component: class vs function  (0) 2022.05.26
react timeline library  (0) 2020.02.24
react에서 (re)hydration(수화,수분보충)의 의미  (0) 2019.12.18
Redux Study  (0) 2019.09.27
react란  (0) 2019.09.02

+ Recent posts