Definitelytyped: تحتاج إلى أمثلة React.Children.map () و React.cloneElement ()

تم إنشاؤها على ٢٦ أكتوبر ٢٠١٦  ·  8تعليقات  ·  مصدر: DefinitelyTyped/DefinitelyTyped

ينقص React.Children.map() مثالًا جيدًا ، ولا أفهم كيفية كتابته:

/*
<CheckboxGroup ...>
  <Checkbox ... />
  <Checkbox ... />
  <Checkbox ... />
</CheckboxGroup>
*/

// Child
class Checkbox extends React.Component<CheckboxProps, void> {
  // ...
}

// Parent
class CheckboxGroup extends React.Component<CheckboxGroupProps, void> {
  // ...

  render() {
    const checkboxes = React.Children.map(this.props.children, checkbox =>
      React.cloneElement(checkbox, {
        name: this.props.name,
        checked: this.props.checkedValues.includes(checkbox.props.value),
        onChange: this.handleCheckboxChange.bind(this)
      })
    );

    return (
      <div>
        {checkboxes}
      </div>
    );
  }
}

(مثال شائع جدًا ، راجع http://stackoverflow.com/a/32371612/990356)

  • كيف تكتب this.props.children ؟
  • كيف تكتب React.cloneElement() ؟
  • كيف تكتب React.Children.map() ؟

في معظم الأوقات ينتهي بي الأمر بالخطأ التالي: Type 'string' is not assignable to type 'ReactElement<any>' ، راجع # 8131

التعليق الأكثر فائدة

سؤال:

const checkboxes = React.Children.map(this.props.children, checkbox =>
  React.cloneElement(checkbox, {
    name: this.props.name,
    checked: this.props.checkedValues.includes(checkbox.props.value),
    onChange: this.handleCheckboxChange.bind(this)
  })
);

حل:

const checkboxes = React.Children.map(props.children, (checkbox: React.ReactElement<CheckboxPropsInternal>) =>
  React.cloneElement(checkbox, {
    checked: props.checkedValues.includes(checkbox.props.value),
    onChange: handleCheckboxChange
  })
);

ال 8 كومينتر

الرجاء إرسال طلب سحب. سوف أراجعها.

vvakame لا أستطيع ، لا أفهم كيف من المفترض أن يعمل

أنا أيضا. يرجى إجراء محادثات مع مؤلفي التعريف.

ستحتاج إلى كتابة التعليق التوضيحي أو تأكيد الكتابة checkbox صراحة لأنه لا يوجد ضمان بأن this.props.children لا يحتوي على قيم غير ReactElement. على سبيل المثال:

React.Children.map(this.props.children, (checkbox: React.ReactElement<CheckboxProps>) => 
    React.cloneElement(checkbox) // should be ok
);

vsiao thx كثيرا ، إنه يعمل!

سؤال:

const checkboxes = React.Children.map(this.props.children, checkbox =>
  React.cloneElement(checkbox, {
    name: this.props.name,
    checked: this.props.checkedValues.includes(checkbox.props.value),
    onChange: this.handleCheckboxChange.bind(this)
  })
);

حل:

const checkboxes = React.Children.map(props.children, (checkbox: React.ReactElement<CheckboxPropsInternal>) =>
  React.cloneElement(checkbox, {
    checked: props.checkedValues.includes(checkbox.props.value),
    onChange: handleCheckboxChange
  })
);

tkrotoff ، يمكنك أيضًا القيام بذلك:

    React.Children.map(this.props.children, (child: number) => {
      return child + 1
    })

هذا والحل المقترح يستفيدان فقط من حقيقة أن React.Children.map غير مكتوب بقوة. ربما تكون قد استخدمت أيضًا any بدلاً من النوع Checkbox نظرًا لعدم وجود ضمان بأن هذا سيكون نوع الأطفال. هذا يعني أنه من المحتمل أن يكون لديك أخطاء في وقت التشغيل إذا أخطأ أي شخص في استخدام المكون عن طريق تمرير سلسلة.

وماذا عن هذا:

class Slot extends React.PureComponent {
  render () {
    return this.props.children
  }
}

const isReactElement = (obj: {}): obj is React.ReactElement<{}> => {
  return obj.hasOwnProperty('type')
}

const isSlot = (obj: {}): obj is Slot => {
  return isReactElement(obj) && obj.type === Slot
}

const getSlots = (children: React.ReactNode) => React.Children.map(children, (child: React.ReactChild): JSX.Element | null => {
  if (isReactElement(child) && isSlot(child)) {
    return child
  }

  return null
})

class ComponentWithSlots extends React.PureComponent {
  render () {
    const [header, footer] = getSlots(this.props.children)

    return (
      <div>
        {header}
        <div>
          <h1>Welcome</h1>
          <p>This is my lovely component with slots</p>
        </div>
        {footer}
      </div>
    )
  }
}

class MyComponent extends React.PureComponent {
  render () {
    return (
      <ComponentWithSlots>
        <Slot>My Header!</Slot>
        <Slot>
          <div>github: @variousauthors</div>
        </Slot>
      </ComponentWithSlots>
    )
  }
}

الذي سيعرض:

My Header!
Welcome
This is my lovely component with slots

github: <strong i="17">@variousauthors</strong>

تستفيد هذه الطريقة من نوع المعلومات التي لدينا _do_ ، وهي أن ReactChild قد يكون ReactElement (لقد استخدمت type لاكتشاف ذلك ، لكن يمكنك أن تكون كذلك أكثر حرصًا إذا أردت). يمكننا أيضًا أن نكون أكثر وصفًا وتفصيلًا أن Slot . رأيت مكتبة UI تنفذ نمطًا حيث تم إرفاق فتحات خاصة بالفصول الدراسية. شيء مثل:

<Dropdown>
  <Dropdown.Header>
    <FancyIcon>My Header!</FancyIcon>
  </Dropdown.Header>
  {dropdownItems}
</Dropdown>

بهذه الطريقة يكون المستخدم واضحًا في معنى كل فتحة. يتم ترك بقية الأطفال (أولئك الذين لم يتم تحليلهم كفتحات) في مجموعة تسمى children ويتم عرضهم في عربة التسوق ، مما يسمح للمستخدم بالاستمرار في استخدام children طبيعي مع الاحتفاظ بسلوك خاص لـ فتحات مخصصة.

تحرير: يبدو أن React لديها طريقة React.isValidElement يمكنك استخدامها بدلاً من isReactElement .

تحرير: شيء آخر يمكنك القيام به هو كتابة الخاصية children على المكون الخاص بك ، بحيث لا يُسمح للمستخدم إلا بالمرور في مربعات الاختيار كأطفال. سيساعد هذا في تجنب أخطاء وقت التشغيل هذه.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات