programing

반응 성분에서 특정 유형의 아이만 허용

newsource 2023. 3. 21. 22:12

반응 성분에서 특정 유형의 아이만 허용

나는 가지고 있다Card컴포넌트와 aCardGroup컴포넌트입니다.또한 에러를 발생시키고 싶습니다.CardGroup그렇지 않은 아이가 있다Card구성 요소들.이게 가능한가요?아니면 제가 잘못된 문제를 해결하려고 하는 건가요?

Respect 0.14+ 및 ES6 클래스를 사용하는 경우 솔루션은 다음과 같습니다.

class CardGroup extends Component {
  render() {
    return (
      <div>{this.props.children}</div>
    )
  }
}
CardGroup.propTypes = {
  children: function (props, propName, componentName) {
    const prop = props[propName]

    let error = null
    React.Children.forEach(prop, function (child) {
      if (child.type !== Card) {
        error = new Error('`' + componentName + '` children should be of type `Card`.');
      }
    })
    return error
  }
}

각 아이에 대해 displayName을 사용할 수 있으며 다음 유형을 통해 액세스할 수 있습니다.

for (child in this.props.children){
  if (this.props.children[child].type.displayName != 'Card'){
    console.log("Warning CardGroup has children that aren't Card components");
  }  
}

어린이는 소품일 뿐이므로 커스텀 propType 함수를 사용하여 어린이를 검증할 수 있습니다.자세한 내용을 원하시면 기사도 작성했습니다.

var CardGroup = React.createClass({
  propTypes: {
    children: function (props, propName, componentName) {
      var error;
      var prop = props[propName];

      React.Children.forEach(prop, function (child) {
        if (child.type.displayName !== 'Card') {
          error = new Error(
            '`' + componentName + '` only accepts children of type `Card`.'
          );
        }
      });

      return error;
    }
  },

  render: function () {
    return (
      <div>{this.props.children}</div>
    );
  }
});

TypeScript 버전을 사용하는 사용자용.다음과 같이 구성 요소를 필터링/수정할 수 있습니다.

this.modifiedChildren = React.Children.map(children, child => {
            if (React.isValidElement(child) && (child as React.ReactElement<any>).type === Card) {
                let modifiedChild = child as React.ReactElement<any>;
                // Modifying here
                return modifiedChild;
            }
            // Returning other components / string.
            // Delete next line in case you dont need them.
            return child;
        });

를 사용합니다.React.Children.forEach아이들에 대해 반복하고 사용하는 방법name유형을 확인할 속성:

React.Children.forEach(this.props.children, (child) => {
    if (child.type.name !== Card.name) {
        console.error("Only card components allowed as children.");
    }
}

사용하는 것을 추천합니다.Card.name대신'Card' 나은 유지 보수와 안정성을 위해 끈을 사용합니다.

참조: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

유형 불일치 오류를 피하기 위해 유형 스크립트를 사용하는 경우 "Child.type"과 함께 "React.isValidElement(child)"를 사용해야 합니다.

React.Children.forEach(props.children, (child, index) => {
  if (React.isValidElement(child) && child.type !== Card) {
    error = new Error(
      '`' + componentName + '` only accepts children of type `Card`.'
    );
  }
});

소품을 추가할 수 있습니다.Card컴포넌트 및 컴포넌트를 사용하여CardGroup요소.이것이 리액트에서 이를 달성하는 가장 안전한 방법입니다.

이 소품은 defaultProp로 추가할 수 있으므로 항상 사용할 수 있습니다.

class Card extends Component {

  static defaultProps = {
    isCard: true,
  }

  render() {
    return (
      <div>A Card</div>
    )
  }
}

class CardGroup extends Component {

  render() {
    for (child in this.props.children) {
      if (!this.props.children[child].props.isCard){
        console.error("Warning CardGroup has a child which isn't a Card component");
      }
    }

    return (
      <div>{this.props.children}</div>
    )
  }
}

를 사용하여 Card 컴포넌트가 실제로 Card 컴포넌트인지 확인type또는displayName님은, https://github.com/facebook/react/issues/6167#issuecomment-191243709 에 나타나 있듯이, 실가동시에 동작하지 않을 가능성이 있기 때문에 안전하지 않습니다.

이를 위해 커스텀 PropType을 만들었습니다.equalTo이렇게 쓸 수 있어요

class MyChildComponent extends React.Component { ... }

class MyParentComponent extends React.Component {
  static propTypes = {
    children: PropTypes.arrayOf(PropTypes.equalTo(MyChildComponent))
  }
}

지금이다,MyParentComponent어린애들만 받아들인다MyChildComponent이런 html 요소를 확인할 수 있습니다.

PropTypes.equalTo('h1')
PropTypes.equalTo('div')
PropTypes.equalTo('img')
...

구현은 다음과 같습니다.

React.PropTypes.equalTo = function (component) {
  return function validate(propValue, key, componentName, location, propFullName) {
    const prop = propValue[key]
    if (prop.type !== component) {
      return new Error(
        'Invalid prop `' + propFullName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  };
}

여러 가지 유형 중 하나를 받아들이도록 쉽게 확장할 수 있습니다.아마도...

React.PropTypes.equalToOneOf = function (arrayOfAcceptedComponents) {
...
}
static propTypes = {

  children : (props, propName, componentName) => {
              const prop = props[propName];
              return React.Children
                       .toArray(prop)
                       .find(child => child.type !== Card) && new Error(`${componentName} only accepts "<Card />" elements`);
  },

}

React 요소의 유형을 검증할 수 있는 패키지를 공개했습니다.https://www.npmjs.com/package/react-element-proptypes :

const ElementPropTypes = require('react-element-proptypes');

const Modal = ({ header, items }) => (
    <div>
        <div>{header}</div>
        <div>{items}</div>
    </div>
);

Modal.propTypes = {
    header: ElementPropTypes.elementOfType(Header).isRequired,
    items: React.PropTypes.arrayOf(ElementPropTypes.elementOfType(Item))
};

// render Modal 
React.render(
    <Modal
       header={<Header title="This is modal" />}
       items={[
           <Item/>,
           <Item/>,
           <Item/>
       ]}
    />,
    rootElement
);

올바른 아동 컴포넌트를 검증하기 위해 react children forach와 Custom validation proptypes사용을 조합합니다.이것에 의해, 마지막에 다음과 같은 것이 가능하게 됩니다.

HouseComponent.propTypes = {
children: PropTypes.oneOfType([(props, propName, componentName) => {
    let error = null;
    const validInputs = [
    'Mother',
    'Girlfried',
    'Friends',
    'Dogs'
    ];
    // Validate the valid inputs components allowed.
    React.Children.forEach(props[propName], (child) => {
            if (!validInputs.includes(child.type.name)) {
                error = new Error(componentName.concat(
                ' children should be one of the type:'
                    .concat(validInputs.toString())
            ));
        }
    });
    return error;
    }]).isRequired
};

보시는 바와 같이 가 올바른 유형의 이름으로 배열되어 있습니다.

한편, Airbnb/prop-type 라이브러리에서 componentWithName이라는 동일한 결과를 얻을 수 있는 기능도 있습니다.자세한 내용은 이쪽에서 확인하실 수 있습니다.

HouseComponent.propTypes = {
    children: PropTypes.oneOfType([
        componentWithName('SegmentedControl'),
        componentWithName('FormText'),
        componentWithName('FormTextarea'),
        componentWithName('FormSelect')
    ]).isRequired
};

이것이 도움이 되기를 바랍니다:)

제안된 접근방식을 여러 개 검토했지만, 모두 신뢰할 수 없거나 지나치게 복잡하여 보일러 플레이트로 사용할 수 없는 것으로 판명되었습니다.이하의 실장에 대해 결정.

class Card extends Component {
  // ...
}

class CardGroup extends Component {
  static propTypes = {
    children: PropTypes.arrayOf(
      (propValue, key, componentName) => (propValue[key].type !== Card)
        ? new Error(`${componentName} only accepts children of type ${Card.name}.`)
        : null
    )
  }
  // ...
}

주요 아이디어는 다음과 같습니다.

  1. 의 「」를 합니다.PropTypes.arrayOf()
  2. 하다를 통해서 .propValue[key].type !== Card
  3. 치환 사용${Card.name}

Library react-element-proptypes는 이 기능을 구현합니다.ElementPropTypes.elementOfType():

import ElementPropTypes from "react-element-proptypes";

class CardGroup extends Component {
  static propTypes = {
    children: PropTypes.arrayOf(ElementPropTypes.elementOfType(Card))
  }
  // ...
}

간단하고 생산성이 뛰어난 체크.Card Group 컴포넌트 상부에 있는 다음 작업을 수행합니다.

const cardType = (<Card />).type;

그런 다음, 아이에 대해 반복할 때:

React.children.map(child => child.type === cardType ? child : null);

가 드러나지컴포넌트/하여 with서서서서서/서 an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an를 만들 수 있다는 것입니다.이 컴포넌트는 필요한 클래스를 공개하지 않고instanceof을을확확확확

유형을 확인합니다.

props.children.forEach(child =>
  console.assert(
    child.type.name == "CanvasItem",
    "CanvasScroll can only have CanvasItem component as children."
  )
)

이 투고와 관련하여, 저는 비슷한 문제를 발견했습니다.아이가 Tooltip 컴포넌트의 여러 아이콘 중 하나일 경우 오류를 발생시켜야 했습니다.

// 아이콘/index.ts

export {default as AddIcon} from './AddIcon';
export {default as SubIcon} from './SubIcon';
...

// 컴포넌트/Tooltip.tsx

import { Children, cloneElement, isValidElement } from 'react';
import * as AllIcons from 'common/icons';
...
const Tooltip = ({children, ...rest}) => {
   Children.forEach(children, child => {
      // ** Inspired from this post
      const reactNodeIsOfIconType = (node, allIcons) => {
         const iconTypes = Object.values(allIcons);
         return iconTypes.some(type => typeof node === 'object' && node !== null && node.type === type);
      };
    
      console.assert(!reactNodeIsOfIconType(child, AllIcons),'Use  some other component instead...')
   })
   ...
   return Children.map(children, child => {
      if (isValidElement(child) {
         return cloneElement(child, ...rest);
      }
      return null;
   });
}

언급URL : https://stackoverflow.com/questions/27366077/only-allow-children-of-a-specific-type-in-a-react-component