Рендеринг любого дочернего компонента с подпорками из строки - PullRequest
1 голос
/ 29 января 2020

У меня должна быть возможность вызывать компонент контейнера и отображать любой из списка дочерних компонентов из строки.

Все дети будут выглядеть примерно так:

<ChildOne store={store} name="child-one" foo="bar" />
<ChildTwo store={store} name="child-two" foo="bar" />
<ChildThree store={store} name="child-three" foo="bar" />

Как видите, все реквизиты одинаковы, кроме самого имени компонента и name проп.

Контейнер должен называться так, в идеале:

<Container child='child-one' />

, но я также подойдет для любой другой реализации, которая дает тот же результат. Я уже давно понял, как это сделать, но для этого нужно повторить много кода и поместить в свой контейнер switch, поэтому я действительно не доволен этим решением.

Контейнер сам по себе будет чистым компонентом (хотя я могу изменить это, если мне абсолютно необходимо, и я представляю, что это выглядит примерно так:

const Container = props => <section><some-variable store={store} name={props.name} foo={props.foo}></some-variable></section>

Хотя я не уверен, как заменить деталь some-variable на фактический компонент.

Редактировать: В попытке прояснить мой вопрос. Я написал реальный пример того, что я ожидал сделать, чтобы сделать эту работу (но это не так работать, я думаю, что я близок, и ошибка ниже, вероятно, является результатом глупой ошибки):

import React, { cloneElement } from 'react'

import Perception from '../FormChildPerception'
import PlannedStatus from '../FormChildPlannedStatus'
import Adjudication from '../FormChildAdjudication'

import './styles.scss'

const componentRegistry = [
  {
    name: 'perception',
    element: Perception
  },
  {
    name: 'planned-status',
    element: PlannedStatus
  },
  {
    name: 'adjudication',
    element: Adjudication
  }
]

const Form = props => {
  const component = componentRegistry.find(component => component.name === props.child)

  return (
    <section className="form-container">
      {
        cloneElement(component.element, {
          store: props.store,
          onStoreUpdate: props.onStoreUpdate,
          callbackFunction: props.callbackFunction
        })
      }
    </section>
  )
}
export default Form

Это приводит к следующей ошибке:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Ответы [ 3 ]

1 голос
/ 29 января 2020

Вы можете использовать некоторый помощник, чтобы решить, какой компонент вам нужно использовать. Например -

const components = new Map([
    ["first-child", FirstChildComponent],
    ["second-child", SecondChildComponent],
    ...etc.
]);
const getNecessaryComponent = (componentName = "some default value") => {
    return components.get(componentName);
});

И в вашем контейнере вы можете использовать эту функцию для определения того, какой компонент вам нужно использовать -

const Container = props => {
    const Component = getNecessaryComponent(props.child);
    return (
        <section>
             <Component 
                 store={store}
                 name={props.name}
                 foo={props.foo}
             ></Component>
        </section>
    );
}

Надеюсь, это будет полезно для вас.

1 голос
/ 29 января 2020

Вы можете создать массив классов компонентов и карту

   const Container = ({component: Comp, store, name }) => (
   <section>
     <Comp store={store} name={name}></some-variable>
   </section>
);

const data = [
  [ChildOne, 'child-one'], [ChildTwo, 'child-two'], [ChildThree, 'child-three']
];

{data.map(([Comp, name]) => <Container component={Comp} name={name} store={store} />)}

 
0 голосов
/ 29 января 2020

У меня все заработало, ответом было изменить componentRegistry на следующее:

const componentRegistry = [
  {
    name: 'perception',
    element: <Perception />
  },
  {
    name: 'planned-status',
    element: <PlannedStatus />
  },
  {
    name: 'adjudication',
    element: <Adjudication />
  }
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...