渲染React组件从字符串

huangapple go评论64阅读模式
英文:

Rendering React Components from String

问题

我试图根据用户输入的字符串动态创建多个 React 组件每个字母都应该作为单独的组件呈现

我的计划是从字符串创建一个数组然后对其进行映射返回一个包含每个组件的新数组

我的主要问题是将字母字符串转换为组件的名称

我曾尝试使用 'eval' 找到解决方案但在生产环境中进行了压缩时会失败

*元素类型无效期望一个字符串用于内置组件或一个类/函数用于组合组件),但得到了数字*
英文:

I'm trying to create multiple React components dynamically from a string entered by the user. Each letter is supposed to be rendered as a separate component.

My plan was to create an array from the string and map over it returning each component in a new array.

My main issue is to convert the letter (string) into the component's name.

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

I thought I found a solution using 'eval' but it fails when minified in production.

(Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: number.)

答案1

得分: 2

使用eval()真的没有任何理由,你可以简单地使用字典存储你的组件引用,然后相应地渲染。

请注意,我已经使用i作为键,但你真的不应该使用它,而是依赖于一个稳定的、唯一的标识符。

import A from "./ComponentA";
import B from "./ComponentB";
import C from "./ComponentC";

// 注意:添加了 'D' 以测试不存在的组件
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组件从字符串

然而,我建议你利用React的懒加载和Suspense特性,这样如果用户输入数组不需要所有组件,就不必一次性加载它们。这是一个稍微高级一些的示例:

  • 它允许你输入动态字符串,解析后加载必要的组件
  • 使用React.Suspense + React.lazy执行动态加载
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>
    </>
  );
}

渲染React组件从字符串

英文:

There is really no reason to use eval() at all: you can simply use a dictionary to store your component references, and then render it accordingly.

Note that I have used i as a key, but you really should not use it but instead rely on a stable, unique identifier.

import A from &quot;./ComponentA&quot;;
import B from &quot;./ComponentB&quot;;
import C from &quot;./ComponentC&quot;;

// NOTE: Added &#39;D&#39; to test for component that doesn&#39;t exist
const userInput = &quot;ABCD&quot;;
const userInputArray = userInput.split(&quot;&quot;);

const components = { A, B, C };

export default function App() {
  return userInputArray.map((component, i) =&gt; {
    const Component = components[component];
    if (!Component) return &lt;&gt;&lt;/&gt;;

    return &lt;Component key={i} /&gt;;
  });
}

渲染React组件从字符串

However, what I would recommend is that you take advantage of React lazy loading and suspense feature, so that you don't have to load all components at once if the user input array does not need all of them. It is little more advanced, but here is another proof-of-concept example:

  • It allows you to input dynamic string that is parsed to load in the necessary components
  • It uses React.Suspense + React.lazy to perform dynamic loading
import { lazy, Suspense, useState } from &quot;react&quot;;

const components = {
  A: lazy(() =&gt; import(&quot;./ComponentA&quot;)),
  B: lazy(() =&gt; import(&quot;./ComponentB&quot;)),
  C: lazy(() =&gt; import(&quot;./ComponentC&quot;))
};

export default function App() {
  const [userInput, setUserInput] = useState(&quot;ABCD&quot;);
  return (
    &lt;&gt;
      &lt;input
        type=&quot;text&quot;
        value={userInput}
        onChange={(e) =&gt; setUserInput(e.currentTarget.value)}
      /&gt;
      &lt;Suspense fallback=&quot;Loading...&quot;&gt;
        {userInput.split(&quot;&quot;).map((component, i) =&gt; {
          const Component = components[component.toUpperCase()];
          if (!Component) return &lt;&gt;&lt;/&gt;;

          return &lt;Component key={i} /&gt;;
        })}
      &lt;/Suspense&gt;
    &lt;/&gt;
  );
}

渲染React组件从字符串

huangapple
  • 本文由 发表于 2023年2月10日 05:26:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/75404569.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定