속성을 React 요소로 재정의하거나 설정

12915 단어 reactwebdevjavascript
Photo by Thomas Tastet (Unsplash)

그래서 오랫동안 저는 구성 요소(요소)의 인스턴스를 만들 때 변경할 방법이 없다고 생각했습니다. 이것은 재사용 가능한 구성 요소를 만들 때 일반적으로 저에게 문제였습니다.

그러나 이를 위한 React 도우미 메서드가 있습니다!

React.cloneElement



내가 참조하는 유틸리티는 노출된 cloneElement 함수입니다. 문서에 명시된 대로 이것을 Clone and return a new React element using element as the starting point에 사용할 수 있습니다.

이 함수는 세 개의 인수를 허용합니다(하나는 필수).
  • 복제할 요소(이것은 물론 필수...)
  • 복제된 요소 소품에 대한 spread 소품.
  • 요소에 추가할 새 자식입니다. 생략하면 원래 자식이 남습니다.

  • 예를 들어 가상의 Button 구성 요소에서 클릭 이벤트와 텍스트를 재정의할 수 있습니다.

    
    const buttonElement = (
       <button onClick={() => alert('hello')>Click me!</button>
    )
    
    React.cloneElement(
       buttonElement, 
       { 
          onClick: () => alert('This replaced the original onClick prop')
       },
       "I am the new text"
    ) 
    


    그것이 정말로 그것의 전부입니다. 복제된 요소에는 모든 동일한 소품이 있지만 새 클릭 핸들러가 있습니다. 그리고 아이들은 새로운 텍스트로 대체되었습니다.

    뭔가를 만들 수 있습니다



    이 예제의 코드는 찾을 수 있습니다here.

    작업 목록이 있는 팝업 메뉴를 만들 것입니다. 소비자는 일반 버튼 또는 앵커 요소만 자식으로 추가하고 일관된 스타일과 팝업을 열고 닫는 이벤트 핸들러로 모든 요소를 ​​향상할 것입니다.

    먼저 작은 도우미를 작성하십시오. 이 코드 조각은 자식이 배열이 되도록 하여 맵을 사용할 수 있도록 합니다.

    function toArray(items) {
      if (!items) return [];
      if (Array.isArray(items)) return items;
      return [items];
    }
    


    다음으로 구성품입니다. 그리고 그것은 아주 간단합니다. 열림/닫힘 상태를 처리하는 간단한 상태 후크const [open, setOpen] = useState(false) .

    컴포넌트의 어딘가에서 우리는 자식 컴포넌트를 변경할 것입니다:

    {toArray(children).map((c) =>
       React.cloneElement(c, 
          {
             className: "button",
             style: undefined,
             onClick: function (e) {
             setOpen(false);
             c.props.onClick?.(e)
          }
       })
    )}
    
    


    요소를 복제하고 스타일 및 className 속성을 재정의하여 일관된 스타일을 보장하기만 하면 됩니다.
    onClick 메서드가 향상되었습니다. 즉, 메뉴를 닫지만 기존 onClick 메서드가 정의된 경우 optional chaining (hence the question mark)을 사용하여 기존 onClick 메서드를 호출하는 자체 구현을 추가합니다.

    메뉴 구성 요소의 전체 코드:

    function Menu({ children }) {
      const [open, setOpen] = useState(false);
    
      return (
        <div className="button-menu">
          <button
            className="menu-toggle"
            aria-controls="menu"
            aria-expanded={open}
            onClick={() => setOpen(!open)}
          >
            {open ? "Close" : "Open"}
          </button>
          <div
            id="menu"
            className="button-group"
            style={{ display: open ? "inherit" : "none" }}
          >
            {/*
            This is the important part
            */}
            {toArray(children).map((c) => {
              return React.cloneElement(c, {
                className: "button",
                style: undefined,
                onClick: function (e) {
                  setOpen(false);
                  //eslint-disable-next-line
                  c.props.onClick?.(e);
                }
              });
            })}
          </div>
        </div>
      );
    }
    




    이 접근 방식의 유일한 단점은 Menu 구성 요소 내부의 요소에 대한 키를 설정해야 한다는 것입니다.

    export default function App() {
      return (
        <Menu>
          <button key="a" 
              onClick={() => alert("I am from the button")}
          >
            I am button
          </button>
          <a key="b" href="#something">
            I am an anchor
          </a>
          <div key="c">Divs should not pose as buttons...</div>
        </Menu>
      );
    }
    

    좋은 웹페이지 즐겨찾기