简体   繁体   中英

How can I add React web components to a parent component dynamically?

Let's say I have a bunch of React web components

const ComponentA = () => {
  return (<div>A</div>)
}
const ComponentB = () => {
  return (<div>B</div>)
}
const ComponentC = () => {
  return (<div>C</div>)
}
const ComponentD = () => {
  return (<div>D</div>)
}
const ComponentE = () => {
  return (<div>E</div>)
}

and I have a parent component that renders some of them.

export default function () {
  const [state, setState] = useState({ count: 0, initialized: false, components: [ComponentA, ComponentB, ComponentC] });
  return (
    <FlexLayout>
      {state.components.map((comp, i) => React.createElement(comp, { key: i }))}
    </FlexLayout>
  );
}

This works as I can see my three components A, B, and C are rendered properly. Next, I add a button to add new items dynamically.

export default function () {
  const [state, setState] = useState({ components: [ComponentA, ComponentB, ComponentC] });
  const handler = () => 
  {
    const list = state.components.slice(0);
    list.push(ComponentD);
    setState ({ components : list })
  }

  return (
    <FlexLayout>
      <button onClick={() => setState(handler)}>Add Component</button>
      {state.components.map((comp, i) => React.createElement(comp, { key: i  }))}
    </FlexLayout>
  );
}

This also works when I click the button for the first time. I can see that I have added ComponentD. However, If I try to add one more instance of ComponentD the app crashes with the following error:

在此处输入图像描述

What is causing this loss of scope where my components are no longer available to the parent?

Some feedback:

  • Storing entire components in state is an anti pattern. Instead, store IDs in the state. Simpler state will reduce likelihood of bugs.
  • as @Mary said, your handler was incorrectly assigned.

Here's a working example:

const ComponentA = () => {
  return (<div>A</div>)
}
const ComponentB = () => {
  return (<div>B</div>)
}
const ComponentC = () => {
  return (<div>C</div>)
}
const ComponentD = () => {
  return (<div>D</div>)
}

const componentMap = {
  a: ComponentA,
  b: ComponentB,
  c: ComponentC,
  d: ComponentD,
}

export default function () {
  const [components, setComponents] = useState([
    'a','b','c',
  ]);
  const handler = () => {
    setComponents ( [...components, 'd'] );
  }

  return (
    <FlexLayout>
      <button onClick={handler}>Add Component</button>
      {components.map(ID => {
        const Component = componentMap[ID];
        return <Component key={ID}/>
      })}
    </FlexLayout>
  );
}

Live Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM