Tên thành phần động React / JSX

182
Sam 2015-04-26 23:23.

Tôi đang cố gắng kết xuất động các thành phần dựa trên loại của chúng.

Ví dụ:

var type = "Example";
var ComponentName = type + "Component";
return <ComponentName />; 
// Returns <examplecomponent />  instead of <ExampleComponent />

Tôi đã thử giải pháp được đề xuất ở đây Tên thành phần động React / JSX

Điều đó đã gây ra lỗi cho tôi khi biên dịch (sử dụng Browserify cho gulp). Nó mong đợi XML nơi tôi đang sử dụng cú pháp mảng.

Tôi có thể giải quyết vấn đề này bằng cách tạo một phương thức cho mọi thành phần:

newExampleComponent() {
    return <ExampleComponent />;
}

newComponent(type) {
    return this["new" + type + "Component"]();
}

Nhưng điều đó có nghĩa là một phương pháp mới cho mọi thành phần tôi tạo. Phải có một giải pháp thanh lịch hơn cho vấn đề này.

Tôi rất cởi mở với các đề xuất.

11 answers

175
Alexandre Kirszenberg 2015-04-27 00:07.

<MyComponent />biên dịch thành React.createElement(MyComponent, {}), trong đó yêu cầu một chuỗi (thẻ HTML) hoặc một hàm (ReactClass) làm tham số đầu tiên.

Bạn chỉ có thể lưu trữ lớp thành phần của mình trong một biến có tên bắt đầu bằng chữ hoa. Xem thẻ HTML so với Thành phần React .

var MyComponent = Components[type + "Component"];
return <MyComponent />;

biên dịch thành

var MyComponent = Components[type + "Component"];
return React.createElement(MyComponent, {});
158
gmfvpereira 2016-12-01 09:01.

Tài liệu chính thức về cách xử lý các tình huống như vậy có sẵn tại đây: https://facebook.github.io/react/docs/jsx-in-depth.html#choosing-the-type-at-runtime

Về cơ bản nó nói:

Sai lầm:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
    photo: PhotoStory,
    video: VideoStory
};

function Story(props) {
    // Wrong! JSX type can't be an expression.
    return <components[props.storyType] story={props.story} />;
}

Chính xác:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
    photo: PhotoStory,
    video: VideoStory
};

function Story(props) {
    // Correct! JSX type can be a capitalized variable.
    const SpecificStory = components[props.storyType];
    return <SpecificStory story={props.story} />;
}
12
Estus Flask 2019-04-21 21:08.

Cần có một vùng chứa ánh xạ tên thành phần đến tất cả các thành phần được cho là được sử dụng động. Các lớp thành phần nên được đăng ký trong một vùng chứa bởi vì trong môi trường mô-đun, không có nơi nào duy nhất mà chúng có thể được truy cập. Các lớp thành phần không thể được xác định bằng tên của chúng mà không chỉ định chúng một cách rõ ràng vì chức năng nameđược rút gọn trong quá trình sản xuất.

Bản đồ thành phần

Nó có thể là đối tượng đơn giản:

class Foo extends React.Component { ... }
...
const componentsMap = { Foo, Bar };
...
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;

Hoặc Mapví dụ:

const componentsMap = new Map([[Foo, Foo], [Bar, Bar]]);
...
const DynamicComponent = componentsMap.get(componentName);

Đối tượng thuần túy phù hợp hơn vì nó được hưởng lợi từ tốc ký tài sản.

Mô-đun thùng

Một mô-đun thùng với các tệp xuất được đặt tên có thể hoạt động như một bản đồ:

// Foo.js
export class Foo extends React.Component { ... }

// dynamic-components.js
export * from './Foo';
export * from './Bar';

// some module that uses dynamic component
import * as componentsMap from './dynamic-components';

const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;

Điều này hoạt động tốt với một lớp cho mỗi kiểu mã mô-đun.

Người trang trí

Trình trang trí có thể được sử dụng với các thành phần lớp cho đường cú pháp, điều này vẫn yêu cầu chỉ định tên lớp một cách rõ ràng và đăng ký chúng trong một bản đồ:

const componentsMap = {};

function dynamic(Component) {
  if (!Component.displayName)
    throw new Error('no name');

  componentsMap[Component.displayName] = Component;

  return Component;
}

...

@dynamic
class Foo extends React.Component {
  static displayName = 'Foo'
  ...
}

Một trình trang trí có thể được sử dụng làm thành phần bậc cao hơn với các thành phần chức năng:

const Bar = props => ...;
Bar.displayName = 'Bar';

export default dynamic(Bar);

Việc sử dụng thuộc tính không chuẩndisplayName thay vì ngẫu nhiên cũng có lợi cho việc gỡ lỗi.

10
Sam 2015-04-26 23:58.

Tôi đã tìm ra một giải pháp mới. Xin lưu ý rằng tôi đang sử dụng các mô-đun ES6 nên tôi đang yêu cầu lớp học. Thay vào đó, bạn cũng có thể xác định một lớp React mới.

var components = {
    example: React.createFactory( require('./ExampleComponent') )
};

var type = "example";

newComponent() {
    return components[type]({ attribute: "value" });
}
7
Ray 2015-11-21 10:17.

Nếu các thành phần của bạn là toàn cầu, bạn có thể chỉ cần làm:

var nameOfComponent = "SomeComponent";
React.createElement(window[nameOfComponent], {});

6
Ricardo Pedroni 2016-08-20 08:27.

Đối với một thành phần trình bao bọc, một giải pháp đơn giản là chỉ sử dụng React.createElementtrực tiếp (sử dụng ES6).

import RaisedButton from 'mui/RaisedButton'
import FlatButton from 'mui/FlatButton'
import IconButton from 'mui/IconButton'

class Button extends React.Component {
  render() {
    const { type, ...props } = this.props

    let button = null
    switch (type) {
      case 'flat': button = FlatButton
      break
      case 'icon': button = IconButton
      break
      default: button = RaisedButton
      break
    }

    return (
      React.createElement(button, { ...props, disableTouchRipple: true, disableFocusRipple: true })
    )
  }
}
5
Stalinko 2020-05-01 21:33.

Trên tất cả các tùy chọn với bản đồ thành phần, tôi không tìm thấy cách đơn giản nhất để xác định bản đồ bằng cú pháp ngắn ES6:

import React from 'react'
import { PhotoStory, VideoStory } from './stories'

const components = {
    PhotoStory,
    VideoStory,
}

function Story(props) {
    //given that props.story contains 'PhotoStory' or 'VideoStory'
    const SpecificStory = components[props.story]
    return <SpecificStory/>
}
1
AmerllicA 2020-02-14 13:06.

Giả sử chúng ta có một flag, không khác với statehoặc props:

import ComponentOne from './ComponentOne';
import ComponentTwo from './ComponentTwo';

~~~

const Compo = flag ? ComponentOne : ComponentTwo;

~~~

<Compo someProp={someValue} />

Với cờ Compođiền bằng một trong ComponentOnehoặc ComponentTwovà sau đó Compocó thể hoạt động giống như một Thành phần React.

1
Arthur Z. 2020-05-19 06:02.

Có một bản đồ trông không đẹp chút nào với một lượng lớn các thành phần. Tôi thực sự ngạc nhiên rằng không ai đề xuất điều gì đó như thế này:

var componentName = "StringThatContainsComponentName";
const importedComponentModule = require("path/to/component/" + componentName).default;
return React.createElement(importedComponentModule); 

Điều này đã thực sự giúp ích cho tôi khi tôi cần kết xuất một lượng lớn các thành phần được tải ở dạng mảng json.

0
1-14x0r 2017-10-03 18:41.

Chúng tôi nghi ngờ rằng chúng tôi muốn truy cập các chế độ xem khác nhau với tải thành phần động. Đoạn mã sau cung cấp một ví dụ hoạt động về cách thực hiện điều này bằng cách sử dụng một chuỗi được phân tích cú pháp từ chuỗi tìm kiếm của một url.

Giả sử chúng ta muốn truy cập một trang 'snozberrys' với hai chế độ xem duy nhất bằng cách sử dụng các đường dẫn url sau:

'http://localhost:3000/snozberrys?aComponent'

'http://localhost:3000/snozberrys?bComponent'

chúng tôi xác định bộ điều khiển chế độ xem của chúng tôi như sau:

import React, { Component } from 'react';
import ReactDOM from 'react-dom'
import {
  BrowserRouter as Router,
  Route
} from 'react-router-dom'
import AComponent from './AComponent.js';
import CoBComponent sole from './BComponent.js';

const views = {
  aComponent: <AComponent />,
  console: <BComponent />
}

const View = (props) => {
  let name = props.location.search.substr(1);
  let view = views[name];
  if(view == null) throw "View '" + name + "' is undefined";
  return view;
}

class ViewManager extends Component {
  render() {
    return (
      <Router>
        <div>
          <Route path='/' component={View}/>
        </div>
      </Router>
    );
  }
}

export default ViewManager

ReactDOM.render(<ViewManager />, document.getElementById('root'));
0
jchapron 2020-11-11 00:58.

Với sự ra đời của React.lazy , giờ đây chúng ta có thể sử dụng một cách tiếp cận động thực sự để nhập thành phần và hiển thị nó.

import React, { lazy, Suspense } from 'react';

const App = ({ componentName, ...props }) => {
  const DynamicComponent = lazy(() => import(`./${componentName}`));
    
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <ComponentName {...props} />
    </Suspense>
  );
};

Cách tiếp cận này tất nhiên tạo ra một số giả định về hệ thống phân cấp tệp và có thể làm cho mã dễ bị phá vỡ.

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Xem đoạn giới thiệu cho bộ phim chuyển thể đầy khói lửa, có sự góp mặt của ngôi sao Edward Norton từ phim Motherless Brooklyn của Jonathan Lethem

Xem đoạn giới thiệu cho bộ phim chuyển thể đầy khói lửa, có sự góp mặt của ngôi sao Edward Norton từ phim Motherless Brooklyn của Jonathan Lethem

Edward Norton đã muốn đưa cuốn tiểu thuyết Motherless Brooklyn của Jonathan Lethem's Joycean 1999 lên màn ảnh kể từ khi nó được xuất bản. Bây giờ, 20 năm sau, một đoạn giới thiệu đã xuất hiện cho câu chuyện sôi nổi, đưa câu chuyện của Lethem trở lại những năm 1950 với rất nhiều gương mặt quen thuộc.

Cách dễ dàng chọn không tham gia trọng tài ràng buộc thẻ Apple

Cách dễ dàng chọn không tham gia trọng tài ràng buộc thẻ Apple

Có thích thú khi sử dụng Thẻ Apple mới của bạn không? Trước khi bạn bắt đầu chi tiêu, có một nhiệm vụ bổ sung cần xem xét: chọn không tham gia trọng tài ràng buộc. Bạn sẽ phát hiện ra các điều khoản trọng tài ràng buộc trong nhiều thỏa thuận tài chính vì nó giúp ngăn các ngân hàng và đối tác kinh doanh của họ không phải ra tòa.

Những người chơi Fortnite World Cup không ghi bàn có cảm giác hài hước về điều đó

Những người chơi Fortnite World Cup không ghi bàn có cảm giác hài hước về điều đó

Điểm số tại vòng chung kết Fortnite World Cup Solo hôm nay là rất lớn, với người chiến thắng Bugha ghi được nhiều hơn 26 điểm so với người về thứ hai là Psalm. Nhưng không phải ai cũng có thể giành chiến thắng: Bốn cầu thủ ra về với 0 điểm, nhưng — ít nhất là trên Twitter — họ là những người thể thao tốt về điều đó.

Báo cáo: Cánh cửa tuyển sinh có thể đã mở cho các ứng viên UCLA có mối quan hệ có ảnh hưởng

Báo cáo: Cánh cửa tuyển sinh có thể đã mở cho các ứng viên UCLA có mối quan hệ có ảnh hưởng

Huấn luyện viên trưởng của bộ môn thể dục dụng cụ UCLA Valorie Kondos-Field theo dõi Katelyn Ohashi thi đấu thăng bằng trong trận gặp Stanford tại Pauley Pavilion vào ngày 10 tháng 3 năm 2019 ở Los Angeles, California. Vụ bê bối gian lận tuyển sinh đại học tiết lộ các chi tiết của một quá trình chính thức hóa để đưa những đứa trẻ thất bại của các gia đình giàu có và nổi tiếng vào các trường đại học đáng tin cậy và danh tiếng, sử dụng một "cửa phụ" đắt tiền cho các bậc cha mẹ mà sự giàu có của họ khiến họ không có cơ hội. chỉ cần tài trợ cho một cánh mới trong khuôn viên trường.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Tầm nhìn đám mây phi tập trung của DFINITY Blockchain

Lưu ý của người biên tập: Bạn đang xem tài liệu lỗi thời từ blog DFINITY đang được bảo quản cho mục đích lưu trữ.

Tầm nhìn đám mây phi tập trung của DFINITY Blockchain

Bài đăng này khám phá tầm nhìn về đám mây phi tập trung của nhóm DFINITY và cách nó liên quan đến các nhà cung cấp blockchain truyền thống và đám mây hiện có như Amazon Web Services. Các minh chứng về công nghệ DFINITY được áp dụng bởi một mạng lưới quy mô lớn sẽ được thực hiện vào mùa thu năm 2017, sau đó sẽ được gây quỹ Chính cho quỹ hỗ trợ phi lợi nhuận, với mạng “đám mây mở” dự kiến ​​sẽ ra mắt vào đầu mùa hè năm 2018 .

Language