prosource

React.Children.map 재귀적으로?

probook 2023. 3. 14. 21:43
반응형

React.Children.map 재귀적으로?

HTML 폼을 렌더링하기 위해 리액트 컴포넌트를 만들고 있는데 특정 유형의 하위 컴포넌트에 추가 소품을 추가하기 위해 부모 폼 컴포넌트의 모든 하위 컴포넌트를 반복적으로 반복해야 합니다.

예(JSX의 경우):

<Form>
    <p>Personal Information</p>
    <Input name="first_name" />
    <Input name="last_name" />
    <Input name="email" />
    <Label>
        Enter Your Birthday
        <Input name="birthday" type="date" />
    </Label>
</Form>

이 예에서는 React를 사용하고 있습니다.Form 컴포넌트 내의 Children.map, 다음으로 맵 함수 내의 Children.map을 통해 아이의 "type"과 아이의 "type.displayName"을 체크하여 내가 다루고 있는 요소(네이티브 HTML 요소 또는 ReactElement 중 하나)를 결정합니다.

var newChildren = React.Children.map(this.props.children, function(child) {
    if (is.inArray(child.type.displayName, supportedInputTypes)) {
      var extraChildProps = {
        alertColor: this.props.alertColor,
        displayErrors: this.state.displayErrors
      }
      return React.cloneElement(child, extraChildProps);
    } else {
      return child;
    }
  }.bind(this));

내 문제는 리액트야Children.map은 이.props.children을 얄팍하게 반복할 뿐이며, 자녀 등의 자녀도 체크해 주셨으면 합니다.오류 표시 시기, 오류 메시지 표시 색상 등을 알 수 있도록 입력 컴포넌트에만 소품을 추가해야 합니다.위의 예에서는 생일 입력이 라벨 컴포넌트로 랩되어 있기 때문에 필요한 소품을 받지 않습니다.

리액트를 위한 모든 계획Children.map은 "재귀적" 모드 또는 제가 하려는 것을 달성할 수 있는 다른 유틸리티를 가지고 있습니까?

마지막으로 모든 아이(네스트된 아이도 포함)를 매핑하는 단일 함수를 작성하여 작업을 수행합니다(이 경우 클로닝).

React에 내장되어 있지는 않지만, 이것은 확실히 가능합니다.

import React from "react";

function recursiveMap(children, fn) {
  return React.Children.map(children, child => {
    if (!React.isValidElement(child)) {
      return child;
    }

    if (child.props.children) {
      child = React.cloneElement(child, {
        children: recursiveMap(child.props.children, fn)
      });
    }

    return fn(child);
  });
}

위의 복사/붙여넣기를 피하고 싶다면 제가 작성한 이 npm 패키지를 사용할 수도 있습니다.

칠드런 구조를 다루기 위해 작은 도서관을 만들었습니다.여기서 확인할 수 있습니다.

https://github.com/fernandopasik/react-children-utilities

이 경우 deepMap 메서드를 사용할 수 있습니다.

import React from 'react';
import Children from 'react-children-utilities';

var newChildren = Children.deepMap(this.props.children, function(child) {
    if (is.inArray(child.type.displayName, supportedInputTypes)) {
      var extraChildProps = {
        alertColor: this.props.alertColor,
        displayErrors: this.state.displayErrors
      }
      return React.cloneElement(child, extraChildProps);
    } else {
      return child;
    }
}.bind(this));

이 스레드는 실제로 정답을 놓치고 있습니다.

const mapRecursive = (children, callback) => (
  React.Children.map(
    children,
    child => (
      child.props.children
        ? [callback(child), mapRecursive(child.props.children, callback)]
        : callback(child)
    ),
  )
);

컴포넌트 아래의 아이 세트에 소품을 "자동"으로 삽입하려는 경우 컨텍스트를 사용할 수도 있습니다.이를 통해 속성, 기능 등을 부모 컴포넌트에서 제공하여 자녀 컴포넌트에 "제공"할 수 있습니다.childContextTypes그리고.getChildContext()자녀에게 '요청'을 하게 합니다.contextTypes.

승인된 답변의 내 타이프스크립트 버전입니다.


const recursiveMap = (
  children: ReactElement[],
  fn: (child: ReactElement) => ReactElement
): ReactElement[] => {
  return React.Children.map(children, child => {
    if (!React.isValidElement(child)) {
      return child;
    }

    if ((child as ReactElement).props.children) {
      const props = {
        children: recursiveMap((child as ReactElement).props.children, fn)
      }
      child = React.cloneElement(child, props);
    }

    return fn(child);
  });
}

이에 대한 간단한 답변은 React 0.14 시점에서는 현재 가능하지 않다는 것입니다.FakeRainBrigand가 언급했듯이, 어쨌든 코드 냄새일 가능성이 높기 때문에 구현의 재평가를 촉구할 것입니다.

내 경우 목록의 항목을 렌더링하는 재귀 함수를 쓰고 그 하위 함수를 작성합니다.

export const MenuCatalog: FC = () => {
return (
    <div style = {{display: 'flex', flexDirection: 'column'}>
        {recursive(testMenuData)}
    </div>
)
}

네스트된 배열:

const testMenuData = [
{
    name: '1',
    children: []
},
{
    name: '1',
    children: [
        {
            name: 'sub 1',
            children: []
        },
        {
            name: 'sub 2',
            children: []
        },
        {
            name: 'sub 3',
            children: [
                {
                    name: 'sub sub 1',
                    children: []
                },
                {
                    name: 'sub sub 2',
                    children: []
                },
                {
                    name: 'sub sub 3',
                    children: []
                }
            ]
        }
    ]
},
{
    name: '3',
    children: []
},
]

재귀 함수:

const recursive = (array: any, isChild?: boolean) => {
return (
    array.map(item => (
        <>
            <CatalogMenuItem isChild = {isChild} name={item.name}/>
            {item?.children.length ? recursive(item.children, true) : null }
        </>
    ))
)
} 

및 렌더링 항목에 대한 사용자 지정 구성요소:

export const CatalogMenuItem: FC<{name: string, isChild?: boolean}> = ({name, isChild}) => {
return (
    <div className = {styles.cont} style = {isChild && {marginLeft: 10}}>{name}</div>
)
}

언급URL : https://stackoverflow.com/questions/32916786/react-children-map-recursively

반응형