반응형

반응형
반응형

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].... -> 정상동작
반응형
반응형
react-router-dom
반응형
반응형

아래 함수를 useEffect(,[])에서 못 부름

위치가 문제인가?

setListData
const setListData = () => {
        setCurrent(true);
        noticeSeq.current = null;
        const query = new Query();
        let queryId = '';
        if (currentTab === 1) {
            queryId = '/cmmNotice/selectFarmFaqList';
        }
        if (currentTab === 0) {
            queryId = '/cmmNotice/selectNoticeList';
        }

        if (currentTab === 1) {
            let checkCategory = [];
            let checkboxList, allCheckbox;
            allCheckbox = document.querySelector('#checkallFaqType');
            checkboxList = document.querySelectorAll('._checkboxFaqType');
            if (allCheckbox.checked) {
                for (let i = 0; i < checkboxList.length; i++) {
                    checkCategory.push((checkboxList.item(i)).value)
                };
            } else {
                for (let i = 0; i < checkboxList.length; i++) {
                    if ((checkboxList.item(i)).checked === true) {
                        checkCategory.push((checkboxList.item(i)).value)
                    }
                };
            }
            if (checkCategory.length > 0) {
                query.addParams('cond_check_faq_type', checkCategory);
            }
            srchParamKeyword.current = txtSrchFaq.current.value;
            srchParamCond.current = cmbOptCondFaq.current.value;
        }
        if (currentTab === 0) {
            query.addParams('cond_st_dt', getFromDateStr(new Date()));
            query.addParams('cond_ed_dt', getFromDateStr(new Date()));
            srchParamKeyword.current = txtSrchNotice.current.value;
            srchParamCond.current = cmbOptCondNotice.current.value;
        }

        if (srchParamKeyword.current !== '') {
            if (srchParamCond.current === initialData.dsSearchTypeList[1].VALUE) {
                query.addParams('cond_title', srchParamKeyword.current);
            } else if (srchParamCond.current === initialData.dsSearchTypeList[2].VALUE) {
                query.addParams('cond_content', srchParamKeyword.current);
            } else if (srchParamCond.current === initialData.dsSearchTypeList[0].VALUE) {
                query.addParams('cond_title_content', srchParamKeyword.current);
            }
        }

        query.addParams('cond_use_yn', 'Y');

        const dataManager = one.createDataManger(
            {
                service: 'farmos',
                queryId: queryId
            }
        );

        dataManager.executeQuery(
            query,
            (res) => {
                if (currentTab === 1) {
                }
                if (currentTab === 0) {
                }
                boardList.current.setBoardList(res.result);
            },
            (error) => {
                const message = one.resMsg(error);
                one.alertMsg('', message);
            }
        )
    }
반응형
반응형
const cbxShipDayRef = useRef(new Array(7));
<td>{['월', '화', '수', '목', '금', '토', '일'].map((n, i) =>
 <div key={n}>
  <CheckBoxComponent label={n}
   ref={(el) => { if (el !== null) {
    cbxShipDayRef.current[i] = el;
    cbxShipDayRef.current[i].value = n;
    cbxShipDayRef.current[i].checked = el.checked;
   } }}
   />&nbsp;&nbsp;&nbsp;
  </div>)}
</td>
 

https://velog.io/@rkio/Typescript-React%EC%97%90%EC%84%9C-useRef-%EC%97%AC%EB%9F%AC-%EA%B0%9C-%ED%95%9C%EB%B2%88%EC%97%90-%EC%84%A0%EC%96%B8%ED%95%98%EA%B8%B0useRef-%EB%B0%B0%EC%97%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0

 

[Typescript] React에서 useRef 여러 개 한번에 선언하기(useRef 배열 만들기)

문제 상황 > 필자가 토이 프로젝트를 진행 중에 마주한 고민이다. useRef를 통해서 특정 요소 클릭 시 특정 이미지로 스크롤이 이동하도록 구현하고자 했다. 이 때, 이미지가 5개 사용되었고, 따라

velog.io

 

반응형
반응형

Uncaught Error: The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX.

반응형
반응형
e-checkboxfilter e-filter-popup e-control e-dialog e-lib e-popup e-popup-open {
  width: 282px;
}

-> .e-checkboxfilter .e-filter-popup .e-control .e-dialog .e-lib .e-popup .e-popup-open

로 수정하니까 정상동작함

반응형

+ Recent posts