Я пытаюсь динамически создать несколько компонентов React из строки, введенной пользователем. Каждая буква должна отображаться как отдельный компонент.
Мой план состоял в том, чтобы создать массив из строки и сопоставить его, возвращая каждый компонент в новый массив.
Моя основная проблема - преобразовать букву (строку) в имя компонента.
import React from 'react'
import './App.css'
import A from './ComponentA'
import B from './ComponentB'
import C from './ComponentC'
const userInput = "ABC"
const userInputArray = userInput.split("")
const components = userInputArray.map((comp, index) => {
return (
React.createElement(eval(comp), { key: [index]})
)
})
function App() {
return (
<>
{ components }
</>
)
}
export default App
Я думал, что нашел решение, используя «eval», но оно терпит неудачу при минимизации в производстве.
(Тип элемента недействителен: ожидалась строка (для встроенных компонентов) или класс/функция (для составных компонентов), но получено: число.)
Я думаю, вам следует создать функцию с оператором switch
, которая будет возвращать необходимый компонент для каждой буквы.
На самом деле нет никакой причины использовать eval()
: вы можете просто использовать словарь для хранения ссылок на ваши компоненты, а затем отображать их соответствующим образом.
Обратите внимание, что я использовал i
в качестве ключа, но вам действительно не следует его использовать, а вместо этого полагаться на стабильный уникальный идентификатор.
import A from "./ComponentA";
import B from "./ComponentB";
import C from "./ComponentC";
// NOTE: Added 'D' to test for component that doesn't exist
const userInput = "ABCD";
const userInputArray = userInput.split("");
const components = { A, B, C };
export default function App() {
return userInputArray.map((component, i) => {
const Component = components[component];
if (!Component) return <></>;
return <Component key = {i} />;
});
}
Тем не менее, я бы порекомендовал вам воспользоваться преимуществами ленивой загрузки и приостановки React, чтобы вам не приходилось загружать все компоненты сразу, если массив пользовательского ввода не нуждается во всех из них. Это немного более продвинуто, но вот еще один пример проверки концепции:
import { lazy, Suspense, useState } from "react";
const components = {
A: lazy(() => import("./ComponentA")),
B: lazy(() => import("./ComponentB")),
C: lazy(() => import("./ComponentC"))
};
export default function App() {
const [userInput, setUserInput] = useState("ABCD");
return (
<>
<input
type = "text"
value = {userInput}
onChange = {(e) => setUserInput(e.currentTarget.value)}
/>
<Suspense fallback = "Loading...">
{userInput.split("").map((component, i) => {
const Component = components[component.toUpperCase()];
if (!Component) return <></>;
return <Component key = {i} />;
})}
</Suspense>
</>
);
}
У вас есть строка и вам нужно связанное значение — почему бы не использовать объект?