정보실

웹학교

정보실

Reactjs React Hooks로 아코디언 만들기.

본문

Sematic UI에 따르면 사용자는 아코디언을 사용하여 컨텐츠 섹션 표시를 토글 할 수 있습니다. 

이 포스트에서는 재사용 성이 높은 아코디언 구성 요소를 처음부터 작성합니다. 

우리는 React와 그 후크 API를 사용할 것입니다.


https://smellycode.com/accordion-in-reactjs/ 


Accordion Image 

샘플 아코디언 (코드 및 상자)


아코디언 구성 요소는 다음 구성 요소로 분류 할 수 있습니다.

  1. 내용을 표시하고 숨기는 토글 구성 요소입니다.
  2. 내용을 감싸는 축소 구성 요소입니다.
  3. 그리고 모든 것을 접착 시키는 루트 구성 요소입니다.

루트 구성 요소의 이름을 <Accordion />으로 지정하겠습니다. 아코디언은 자녀에게 필요한 데이터를 제공 할 책임이 있습니다. 

렌더링 props 또는 복합 구성 요소를 사용하여 구현할 수 있습니다. 복합 구성 요소 패턴을 사용하여 아코디언을 쉽게 추론 할 수 있습니다. 

또한 복합 구성 요소 패턴으로 인해 JSX는 의미상 더 의미 있고 아름답습니다.


샘플 아코디언 JSX.


<Accordion>
  <Accordion.Toggle>Click Me</Accordion.Toggle>
  <Accordion.Collapse>Some collapsable text</Accordion.Collapse>
</Accordion>



각 아코디언 구성 요소를 디자인 해 보겠습니다.


<Accordion /> 


아코디언 구성 요소는 컨테이너 역할을합니다. 

요소 소품은 컨테이너 요소 / 구성 요소로 사용됩니다. 

요소의 기본값은 div로 설정되어 있습니다. 

아코디언에는 onToggle, activeEventKey 등의 다른 소품도 있습니다.


참고 : PropTypes 패키지는 유형 확인에 사용됩니다.


const Accordion = ({
  element: Component,
  activeEventKey,
  onToggle,
  children,
  ...otherProps
}) => {
  return <Component {...otherProps}>{children}</Component>;
};

Accordion.propTypes = {
  // Element or Component to be rendered as a parent for accordion.
  element: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

  // `eventKey` of the accordion/section which is active/open
  activeEventKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

  // onToggle callback. (eventKey) => void
  onToggle: PropTypes.func
};

Accordion.defaultProps = {
  // default render as div
  element: 'div'
};


<Accordion.Toggle /> 


이름에서 알 수 있듯이 Accordion.Toggle은 내용을 토글합니다. 

또한 Accordion 구성 요소와 같은 요소 소품도 받습니다. 

Accordion.Collapse 구성 요소에 매핑 된 eventKey 소품이 필요합니다.


const Toggle = ({
  element: Component,
  eventKey,
  onClick,
  children,
  ...otherProps
}) => {
  return <Component {...otherProps}>{children}</Component>;
};

Toggle.propTypes = {
  // Element or Component to be rendered as a toggle.
  element: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

  // `eventKey` of the content to be controlled.
  eventKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
};

Toggle.defaultProps = {
  element: 'div'
};


<Accordion.Collapse /> 


Accordion.Collapse 구성 요소는 콘텐츠를 조건부로 렌더링 합니다. 다른 구성 요소와 마찬가지로 요소 소품도 받습니다.

const Collapse = ({
  element: Component,
  eventKey,
  children,
  ...otherProps
}) => {
  return <Component {...otherProps}>{children}</Component>;
};

Collapse.propTypes = {
  // Wrapper for target content.
  element: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

  // Event key for the content.
  eventKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
};

Collapse.defaultProps = {
  element: 'div'
};


Toggle과 Collapse with Accordion 네임 스페이스를 모두 내보낼 것입니다.


// ...
// Accordion's code
// ...

Accordion.Toggle = Toggle;Accordion.Collapse = Collapse;


우리는 기초를 마련했습니다. 다른 개념을 소개하겠습니다.


useAccordionContext 


각 아코디언 구성 요소에는 아코디언 구성 요소의 일부 데이터가 필요합니다. 

예. Accordion.Collapse는 컨텐츠를 조건부로 표시하려면 activeEventKey를 알아야 합니다. 

Accordion.Toggle은 적절한 매개 변수로 전환 콜백을 호출하기 위해 activeEventKey를 알아야 합니다.


각 아코디언 구성 요소에 소품으로 데이터를 수동으로 전달할 수 있습니다. 

그러나 아코디언 컴포넌트 트리에서의 위치에 대한 지식이 필요합니다. 

React는 이러한 사용 사례에 대한 더 나은 대안을 제공합니다. 

React Context. 컨텍스트 API를 사용하면 모든 수준에서 소품을 수동으로 전달하지 않고도 구성 요소 트리를 통해 데이터를 전달할 수 있습니다.


아코디언을 위한 컨텍스트를 만들어 봅시다.


AccordionContext.js


import React from 'react';

export default React.createContext(null);


아코디언 컨텍스트에 액세스하려면 후크하십시오.


import { useContext } from 'react';
import AccordionContext from '../AccordionContext';

const useAccordionContext = () => {
  const context = useContext(AccordionContext);
  if (!context) {
    throw new Error(
      'Accordion components are compound component. Must be used inside Accordion.'
    );
  }
  return context;
};

export default useAccordionContext;


Accordion은 activeEventKey 속성과 onToggle 메소드를 사용하여 AccordionContext를 초기화합니다.


const Accordion = ({
  element: Component,
  activeEventKey,
  onToggle,
  children,
  ...otherProps
}) => {
  const context = useMemo(() => {    return { activeEventKey, onToggle };  }, [activeEventKey, onToggle]);
  return (    <AccordionContext.Provider value={context}>      <Component {...otherProps}>{children}</Component>
    </AccordionContext.Provider>  );
};


Accordion.Collapse는 컨텍스트에서 activeEventKey를 읽습니다. activeEventKey가 eventKey와 같은 경우 컨텐츠를 렌더링 합니다.


import { useAccordionContext } from '../hooks';
const Collapse = ({
  element: Component,
  eventKey,
  children,
  ...otherProps
}) => {
  const { activeEventKey } = useAccordionContext();  return activeEventKey === eventKey ? (    <Component {...otherProps}>{children}</Component>
  ) : null;};


Accordion.Toggle은 토글 컴포넌트 / 요소를 클릭 할 때 컨텍스트에서 onToggle 함수를 호출합니다.


import { useAccordionContext } from '../hooks';
const useAccordionClick = (eventKey, onClick) => {  const { onToggle, activeEventKey } = useAccordionContext();  return event => {    onToggle(eventKey === activeEventKey ? null : eventKey);    if (onClick) {      onClick(event);    }  };};
const Toggle = ({
  element: Component,
  eventKey,
  onClick,
  children,
  ...otherProps
}) => {
  const accordionClick = useAccordionClick(eventKey, onClick);  return (    <Component onClick={accordionClick} {...otherProps}>      {children}    </Component>  );};


카드 구성 요소를 사용하여 App의 모든 것을 연결 한 후 :


import Accordion from './Accordion';

import Card from './Card';

const content = [
  // items in {question, answer} format
  // ...
  // ...
];

export default function App() {
  const [activeEventKey, setActiveEventKey] = useState(0);

  return (
    <div className="App">
      <Accordion activeEventKey={activeEventKey} onToggle={setActiveEventKey}>
        {content.map(({ question, answer }, index) => (
          <Card key={index}>
            <Accordion.Toggle element={Card.Header} eventKey={index}>
              {question}
              {activeEventKey !== index && <span>👇🏻</span>}
              {activeEventKey === index && <span>👆🏻</span>}
            </Accordion.Toggle>
            <Accordion.Collapse eventKey={index} element={Card.Body}>
              {answer}
            </Accordion.Collapse>
          </Card>
        ))}
      </Accordion>
    </div>
  );
}


제어 가능성 


아코디언 구성 요소는 제어되는 구성 요소입니다. 주가 없습니다. 소품으로 필요한 데이터를 수신합니다 (예 : 활성 섹션 키 activeEventKey, 토글 핸들러 onToggle 등). 

Accordion의 제어 된 특성으로 인해 매우 유연하지만 단점이 있습니다. 

소비자 구성 요소는 필요하지 않은 경우에도 아코디언 상태를 명시 적으로 관리해야 합니다. 

명시적 상태 관리는 때때로 지루할 수 있으며 상용구를 유발할 수 있습니다.


아코디언에는 제어되지 않은 동작이 추가됩니다. 실제 앱에서는 제어 할 수 없는 것을 사용할 수 있습니다.


아코디언을 제어 불가능 / 제어 가능하게 하기 위해 아코디언에 로컬 상태를 소개합니다. 

activeEventKey prop과 동기화 상태를 유지합니다. 

깜박임을 피하기 위해 동기화에 useEffect 대신 useLayoutEffect를 사용합니다 (useEffect와 useLayoutEffect).


로컬 상태의 향상된 아코디언 구성 요소


const useEventKey = (eventKey, onToggle) => {  const [activeEventKey, setActiveEventKey] = useState(eventKey);  useLayoutEffect(() => {    setActiveEventKey(eventKey);  }, [eventKey, onToggle]);  return [activeEventKey, setActiveEventKey];};
const Accordion = ({
  element: Component,
  activeEventKey,
  onToggle,
  children,
  ...otherProps
}) => {
  const [eventKey, setEventKey] = useEventKey(activeEventKey, onToggle);  const handleToggle = useCallback(    eventKey => {      if (activeEventKey !== undefined) {        onToggle(eventKey);        return;      }      setEventKey(eventKey);    },    [activeEventKey, onToggle, setEventKey]  );
  const context = useMemo(() => {
    return {      activeEventKey: eventKey,      onToggle: handleToggle    };  }, [eventKey, handleToggle]);
  return (
    <AccordionContext.Provider value={context}>
      <Component {...otherProps}>{children}</Component>
    </AccordionContext.Provider>
  );
};

Accordion.defaultProps = {
  // default render as div
  element: 'div',

  onToggle: () => {}};


마지막으로, 아코디언의 제어 및 제어되지 않은 형태를 모두 갖춘 앱 구성 요소.


export default function App() {
  const [activeEventKey, setActiveEventKey] = useState(0);
  return (
    <div className="App">
      <h3>Uncontrolled Accordion</h3>      <Accordion>        {content.map(({ question, answer }, index) => (          <Card key={index}>            <Accordion.Toggle element={Card.Header} eventKey={index}>              {index + 1}. {question}            </Accordion.Toggle>            <Accordion.Collapse eventKey={index} element={Card.Body}>              {answer}            </Accordion.Collapse>          </Card>        ))}      </Accordion>      <h3>Controlled Accordion</h3>      <Accordion activeEventKey={activeEventKey} onToggle={setActiveEventKey}>
        {content.map(({ question, answer }, index) => (
          <Card key={index}>
            <Accordion.Toggle element={Card.Header} eventKey={index}>
              {index + 1}. {question}
              {activeEventKey !== index && <span>👇🏻</span>}
              {activeEventKey === index && <span>👆🏻</span>}
            </Accordion.Toggle>
            <Accordion.Collapse eventKey={index} element={Card.Body}>
              {answer}
            </Accordion.Collapse>
          </Card>
        ))}
      </Accordion>
    </div>
  );
}




페이지 정보

조회 72회 ]  작성일20-03-06 21:25

웹학교