Динамический рендер компонентов

Версия 1.1 от Alexandr Fokin на 2023/12/29 14:48

 React + TypeScript
 import { useState, createElement, ElementType } from 'react'

interface componentProp {
    selectedComponent: string,
    prop1: number,    
    onClick: (state: componentProp) => void
};

function Component1(prop: componentProp) {
   return (
       <div>
           <p>component1 {prop.prop1}</p>
           <button
                onClick={() => { prop.onClick({ ...prop, prop1: prop.prop1 + 1 }) }}
           >
                Increment
           </button>
           <button
                onClick={() => { prop.onClick({ ...prop, selectedComponent: "c2" }) }}
           >
                To component2
           </button>
           <button
                onClick={() => { prop.onClick({ ...prop, selectedComponent: "unknow name" }) }}
           >
                Bad component
           </button>
       </div>
    )
}
function Component2(prop: componentProp) {
   return (
       <div>
           <p>component2 {prop.prop1}</p>
           <button
                onClick={() => { prop.onClick({ ...prop, prop1: prop.prop1 + 1 }) }}
           >
                Increment
           </button>
           <button
                onClick={() => { prop.onClick({ ...prop, selectedComponent: "c1" }) }}
           >
                To component1
           </button>
       </div>
    )
}

const mapping = new Map<string, ElementType>()
    .set("c1", Component1)
    .set("c2", Component2);

function App() {

   const [state, setState] = useState<componentProp>(
        {
            selectedComponent: "c1",
            prop1: 10,
            onClick: (q) => {
                setState(q)
            }
        });

   const selectedComponent = mapping.get(state.selectedComponent);

   if (selectedComponent === undefined) {
       return (<>
           <div>Not defined "{state.selectedComponent}"</div>
       </>);
    }

 return (
     <>
         <div>
              {createElement(selectedComponent, state) }
         </div>
     </>
  )
}

export default App
  

 

Теги: