← Home

React

Setup

Package

To install CRA:

npm i create-react-app -g

The library React defines components and their interactions. The library ReactDOM places components in the DOM. They are both included, along with 1700 other packages, in a CRA app.

CRA’s default linter: ESLint

To create an app using CRA:

create-react-app [app-name]

To create an app using CRA with TypeScript:

create-react-app [app-name] --typescript

To start the app:

npm start
npm run start
// at project root folder

NPM scripts are defined in package.json and are run with npm run script. run can be removed when using start.

Default CRA port: http://localhost:3000

App

public/index.html
<div id="root"></div>
src/index.js
import React from "react";
import ReactDOM from "react-DOM";

const App = () => return <h1>Hello</h1>;

ReactDOM.render(
    <App />,
    document.querySelector("#root")
);

JSX

JSX is a dialect of JavaScript that describes DOM nodes after a return statement in a function or inside a render() methods. An element refers to a bundle of JSX.

return <div>Hello!</div>;

Since browsers cannot parse JSX, CRA uses Babel to translate JSX into ES5 JavaScript.

<div>Hello</div>;

// JSX is translated to ordinary JS...

React.createElement("div", null, "Hi there!");

Wrapping and self-closing

A component must always return a single element. If necessary, wrap multiple components in a single one such as a <div> or a <React.Fragment> or a <>.

return (
	<div>
		<MyComponent1 />
		<MyComponent2 />
	</div>
);

In JSX, if you have a multi-line return statement, use brackets to prevent automatic semicolon insertion. (And make sure there are no semicolons outside the JSX but inside the brackets.)

return <div>Hello!</div>;

JSX tags must be self-closed even when their HTML counterparts are not:

<br /> <input /> <img />

Inserting variables and functions

In JSX, you can insert a JavaScript variable, use curly braces:

let name = "john";

return <div>Hello, my name is {name}.</div>;

Or a function:

function getName() {
	return "john";
}

return <div>Hello, my name is {getName()}.</div>;

In JSX, a common error is Objects are not valid as a React child, which means that you are inserting an object inside a component to show text, when you should be passing a string. You can insert an object for styling, but not for showing text.

let text = { name: "john" };

// and inside a component's render method...

return <div>Hello, my name is {text}.</div>;
// → error: `Objects are not valid as a React child`

To fix, reference the property:

return <div>Hello, my name is {text.name}.</div>;

In JSX, only expressions (which return a single value) can be used, not statements (which do not return anything).

<div>{ let x = "hi there" }</div> // error
<div>{ "hi " + "there" }</div> // ok

In JSX, to add styling, use two pairs of curly braces to provide a JavaScript object. The first pair indicates a variable; the second indicates a JavaScript object. In the JavaScript object, the key is the CSS property (in camelCase, if it has a compound property name) and the value is the CSS value, with separation by commas if multiple properties.

<div style={{ backgroundColor: 'red', color: 'white' }}>

Note: camelCase, comma separation and single quotes.

To insert a condition inside JSX, use the ternary expression X ? A : B or logical operators X && Y.

return (
    <div>
        { age > 18 ? "Adult" : "Not adult" }
    <div>
);

You can also place an if condition inside the render() method before the return statement, but this is discouraged due to code duplication.

Renaming HTML tag attributes

In JSX, replace HTML class= with className= because class is a reserved keyword in JavaScript.

<MyComponent className="my-class" />

In JSX, replace HTML for= with htmlFor= because for is a reserved keyword in JavaScript.

<label htmlFor="my-input" />

In JSX, logical operators control rendering:

C && RE; // → if true, then render
C ? R : null; // → if true, then render element; otherwise, do nothing

Example:

{
	result && (
		<Table
			list={result.hits}
			pattern={this.state.searchTerm}
			onDismiss={this.onDismiss}
		/>
	);
}
// if `result` is `true`, `<Table />` is rendered

JSX renames events with camelCase (onClick, onSubmit), whereas HTML events are all lowercase (onclick, onsubmit).

Rendering lists

To render a list, map over the array and return an element containing the item and a key set to the index (or preferably a unique ID) of the item:

const ImageList = props => {
	return props.urls.map((url, ix) => {
		return <img src={url} key={ix} />;
	});
};

Components

A component is a function or a class that produces HTML via JSX for the user, and handles events from the user using event handlers. A component can be:

  • a functional component, or
  • a class component.

Export components using default exports:

// CommentDetail.js
export default CommentDetail;

// app.js
import CommentDetail from "./CommentDetail";

Functional components

A functional component is a function that returns JSX. Use a functional component if the component does not need its own state, unless you are using hooks.

const Title = props => <h1>Hello!</h1>;

const App = () => {
	window.navigator.geolocation.getCurrentPosition();
	return <div>Hello</div>;
};

Class components

A class component is a class that extends React.Component and has a method render() with a return statement that returns JSX. Use a class component if the component needs its own state.

There are two forms for initializing state:

  • long form (with constructor)
  • short form (without constructor)

Long-form state initialization

class Comp extends React.Component {
	constructor(props) {
		super(props);
		this.state = { key: value }; // direct assignment
	}

	render() {
		return <h1>Hello!</h1>;
	}
}

constructor() is called every time the component is instantiated. The constructor must be defined with a props argument (to receive any props passed in) and must contain a call to super(props) (to execute the constructor of parent React.Component).

Below the call to super(props), still inside the constructor, you can assign an object to state directly. This object should be a key with a type-relevant default value, such as '' for string, [] for array and {} for object.

Short-form state initialization

class Comp extends React.Component {
	state = { key: value };

	render() {
		return <h1>Hello!</h1>;
	}
}

If a state is initialized without a constructor, Babel translates this shorthand into a constructor function behind the scenes.


In both cases, the constructor is the only place where you are allowed to assign an object to state directly; this value is used at instantiation. Thereafter, use this.setState(). The procedure is often: call to class method, class method contains call to this.setState() with new data, the state change causes the component to be re-rendered.

Unbinding of this

In class methods, use the fat-arrow syntax to the unbinding of this, i.e., to prevent losing the this reference inside the class method.

class Comp extends React.Component {
	constructor(props) {
		super(props);
		this.state = { key: value };
		// no binding needed
	}

	doSomething = e => {
		// fat-arrow syntax for method
		// ...
	};
}

A second solution is to pass an arrow function directly inside the callback:

<input
	type="text"
	value={this.state.username}
	onChange={(e) => this.doSomething(e))}
/>

Otherwise, you must bind the method:

class Comp extends React.Component {
	constructor(props) {
		super(props);
		this.state = { key: value };
		this.doSomething = this.doSomething.bind(this);
		// binding necessary
	}

	doSomething(e) {
		// ordinary method syntax
		// ...
	}
}

Higher-order components

A higher-order component takes in a component by enclosing it and has access to it via props.children.

App.jsx
<ApprovalCard>
    <CommentDetail />
<ApprovalCard />
ApprovalCard.jsx
const ApprovalCard = props => {
	return <div className="approval-card">{props.children}</div>;
};

Lifecycle methods

Lifecycle methods are methods that can be added to a class component and that are called at certain points along its lifecycle. Lifecycle methods are only used in class components.

When Method
at instantiation constructor()
at every render render()
after insertion into DOM componentDidMount()
after state change or new props componentDidUpdate()
before removal from DOM componentWillUnmount()

Mind the difference:

  • instantiating: creating the component by calling ReactDOM.render() for the base component,
  • rendering: displaying HTML to the user,
  • mounting: inserting the component into the DOM.

render() is called every time JSX becomes HTML shown to the user. A component is rendered and re-rendered much more often than it is mounted or unmounted.

Conventional usage:

  1. Instantiate at constructor() with default state.
  2. render() component with default value.
  3. Do something at componentDidMount() and change state.
  4. Re-render() because of changed state.

Less often, componentDidUpdate() is used at step 5. Remember, componentDidMount() is only called at step 3. It will only be called again if you unmount the component and mount it again.

  • constructor() is often used for initializing state. It is convention not to do data loading inside the constructor.
  • render() is only used for displaying HTML. Do not use this method for data loading or anything else.
  • componentDidMount() is often used for initial data loading. Mind you, only “initial” because it is only called one time: on insertion of the component into the DOM tree.
  • componentDidUpdate() is often used for responsive data loading, i.e. data loading that must occur in response to a state change or new props.
  • componentWillUnmount() is often used for cleanup (invalidating timers, canceling network requests, etc.). It is used less often that the other lifecycle methods.

Rarely used methods

  • shouldComponentUpdate()
  • getDerivedStateFromProps()
  • getSnapshotBeforeUpdate()

Deprecated methods

  • componentWillMount()
  • componentWillReceiveProps()
  • componentWillUpdate()

Props

Props (properties) are data passed from a parent component into a child component. Props are declared on child instantiation. Props are read-only data: if this data will change, then it should not a prop—it should be state.

<CommentDetail author="John" content="Yeah" />

Functional components receive props as argument object: props

const CommentDetail = (props) => { // props = { author: "John" }
	const { author } = props;
	return (
		// ...
	)
}

Class components receive props as a default class property: this.props.

class CommentDetail extends React.Component {
	render() {
		return;
	}
}

In an SFC, props can be destructured directly inside the function signature:

function Search({ value, onChange }) {
	return (
		<form>
			{children}
			<input value={value} onChange={onChange} />
		</form>
	);
}

If text is inserted inside a component, causing two tags instead of a self-closing tag, the text automatically becomes a prop called children.

<MyComponent>Hello there!<MyComponent />
// `this.props.children` is equal to the string `Hello there!`

Default props

const Spinner = props => {
	return (
		<div classNAme="ui active dimmer">
			<div className="ui big text loader">
				{props.message}
				// if empty, "message" in // defaultProps will be used
			</div>
		</div>
	);
};

Spinner.defaultProps = {
	message: "Loading..."
};

State

State is a JavaScript object (class property) relevant to a component. State is data liable to change over time.

State is often used in class components, and it can be used in functional components via hooks.

State is initialized when the component is instantiated. State is changed using this.setState().

Changing state causes its component to re-render. Re-rendering event are not immediate: they are queued for optimization purposes.

When you change state, you are not required to change every key in the object. If there are two keys and values and you change only one pair, the other pair will remain unchanged.

What should go into state?

  • User input (form field values, etc.)
  • Current or selected item (current tab, etc.)
  • Data from server (a list of products, etc.)
  • Open/closed status (modal open/closed, etc.)

State should be changed by the component that owns it.

Do not copy props into state.

Lift state up.

Aim to keep components stateless; lift state up to the component’s parent. A sidebar need not know whether is visible, it is only rendered or not based on the prop handed down from its parent.

Always initialize state properties with a default, even as "", null, etc. instead of creating state properties where none where initialize. This often placates TypeScript.

Controlling inputs

Controlling an input means making a component’s state be the single source of truth for the input’s value= attribute.

Do not store information inside HTML elements.

To control an input, set a handler for its onChange event and set its value= to a state value.

<input
	type="text"
	onChange={this.state.onInputChange} // input sets state
	value={this.state.username} // state sets value
/>

The event handler (class method) receives event as a default argument, from which the value can be extracted:

onInputChange = event => {
	this.setState({ username: event.target.value });
};

The input control sequence is:

  1. User enters input.
  2. Input triggers event handler.
  3. Event handler sets state.
  4. Component re-renders.
  5. Input receives value from state.

Event handler (class method) naming conventions:

  • onInputChange (on + element + event)
  • handleInputChange (handle + element + event)

Fat-arrow syntax for event handlers:

<input
	type="text"
	onChange={e => this.setState(e.target.value)}
	value={this.state.username}
/>

Refs

A ref is a direct reference to a specific DOM element.

To create a ref, use React.createRef() inside the constructor of a class component, and assign the ref to an instance variable. Refs are not intended to change: do not place a ref in state.

Once created, the ref can be used in JSX with the ref= tag. The ref= tag is a JSX tag that will be turned into an HTML element.

class MyComponent extends React.Component {

    constructor(props) {
        super(props);
        this.myRef = React.createRef();
    }

    onInputClick = () => {
        this.myRef.current.focus();
    }

    render() {
        return (
            <input
                type="text"
                ref={this.myRef}
                onClick={this.onInputClick}
            />;
        )
    }
}

To access a ref:

const referencedElement = this.myRef.current;

Calling this.myRef.current.focus() changes the state of the <input> without any React state updates. This makes sense in the case of focusing on an <input>, as we would not want to re-render elements every time we focus on an <input>.

Refs have very limited use cases.

React Router

Setup

$ npm i react-router-dom

Routing

To enable routing, wrap <App /> with <BrowserRouter />.

<BrowserRouter>
	<App />
</BrowserRouter>

Or you can wrap the <Switch /> component directly with <BrowserRouter />:

<BrowserRouter>
	<Switch>
		<Route exact path="/" component={HomePage} />
		<Route path="/users" component={Users} />
	</Switch>
</BrowserRouter>

Continuing with the first option, inside the wrapped <App />, you can return a group of routes with a <Switch /> component containing multiple <Route /> components. The <Switch /> component returns the first matching path. Without <Switch />, all matching routes will render their associated components, i.e. greedy matching.

Each <Route /> has a path= for the URL pattern and a component= for the component to be rendered.

return (
	<Switch>
		<Route exact path="/" component={HomePage} />
		<Route path="/user" component={UserPage} />
	</Switch>
);

If navigated path partially matches the value at path=, the component at component= is rendered. That is, does the navigated path contain the defined path? For instance, /page contains / and /page, so there is a partial match.

Example: If you navigate to myapp.com/, / can contain only /, so only that route will be triggered. However, if you navigate to myapp.com/user, / will match both / and /user, the latter because / partially matches the first character in the second route. To disable partial matching, use exact or exact={true}.

Otherwise, if you are using <Switch /> but the paths are not using exact, order your routes from specific to generic.

For components that should always be visible, instantiate them outside the <BrowserRouter />, at the same level that <BrowserRouter /> is at. However, if the components need to contain React Router-specific functionality (<Link />, <Redirect />, etc.), you can include them inside <BrowserRouter /> but with no associated route, so they are always visible.

Passing props to a routed component

To pass props to a routed component, instead of component= use render= with a fat-arrow function returning the component and the props.

<Route path="/dashboard" render={() => <Dashboard color="green" />} />

Default props in a routed component

A component instantiated via <Route /> carries three default props: history, location and match. To avoid losing them, pass them as props in the argument to the fat-arrow function inside render= and destructure them inside the component with ...props .

<Route
	path="/dashboard"
	render={props => {
		return <Dashboard color="green" {...props} />;
	}}
/>

Route parameters

To pass and retrieve route parameters:

<Route path="/products/:id" component={ProductDetail} {...props} />

Route parameters are inside props.match.params.id.

To make a route parameter optional:

<Route path="/posts/:year?/:month?" component={ProductDetail} {...props} />

Query string parameters

/posts?sortBy=newest

Query string parameters are inside props.location.search.

To extract query strings from location.search, install:

$ npm i query-string

And parse the query string:

queryString.parse(location.search);
// → { "sortBy": "newest" }

Nested routing

You can use <Route /> in a child component, i.e. below the <App /> level.

const Dashboard = ({ match }) => {
    return (
        <div>
            <h1>Admin Dashboard</h1>
            <SideBar />
            <Route path="/admin/users" component={Users}>
            <Route path="/admin/posts" component={Posts}>
        </div>
    );
}

Linking

<Link />, when clicked, updates the URL to the to= value. The updated URL causes a route to be triggered and its associated component to be rendered.

<Link to="/dashboard">Click here to access the Dashboard!</Link>

A <Link /> prevents a full page reload. Preventing server requests is important to prevent the current HTML file (containing JavaScript variables in memory, i.e. React state data) from being dumped and replaced with a brand new HTML file. This is the basis for a single-page app (SPA). Do not use anchor tags <a href="..."> with React Router.

An <a href="..."> tag is for navigation to a different HTML document. A <Link /> component is for navigation to a different <Route /> rendered by React Router.

Redirecting

<Redirect /> is often used for Not Found pages.

<Route path="/products" />
<Route path="/admin" />
<Route path="/not-found" component={NotFound}>
<Route path="/" exact />
<Redirect to="/not-found" />

If the URL is invalid (i.e. does not match any route), the <Redirect /> component will kick in and lead the user to the /not-found route. To redirect to a catch-all route, you can also use a <Route /> with a specified component but without a specified path.

<Redirect /> is also used to rename URLs.

<Switch>
    <Redirect from="/messages" to="/posts" />
    <Route path="/posts" component={Posts}>
</Switch>

Visited URLs are inside props.history.

  • props.history.push() adds a new URL to the user’s navigation history, allowing for back button functionality.
  • props.history.replace() replaces the current URL wth a new URL in the user’s navigation history, not allowing for back button functionality. This is useful for specific scenarios such as redirecting after login, so that the logged in user is not logged out when clicking the back button.

Protecting routes

<Route
	path="/secret-endpoint"
	render={props => {
		if (!isAuthorized) return <Redirect to="/login" />;
		return <Secret {...props} />;
	}}
/>

To extract a reusable <ProtectedRoute /> component:

const ProtectedRoute = ({ component: Component, render, ...rest }) => {
    return (
        <Route
            ...rest // contains `path`
            render={props => {
                if (!isAuthorized) return <Redirect to="/login" />;
                return <Component {...props} />;
            }}
        />
    );
};

Context

Context is global data available to the entire tree of React components, such as the current authenticated user, theme, or preferred language. Normally, this data would be passed down the component tree as props. Context makes this data available without the need for explicitly passing down props, i.e. context makes it unnecessary to pass props through every component.

Usage

  1. Create a context
  2. Provide the context
  3. Consume the context

1. Create a context

Context object

import React from "react";

const ThemeContext = React.createContext();
// has two properties: Context.Provider, Context.Consumer

export default ThemeContext;

You can set a default value for a context object:

const Color = React.createContext("black");
// if no arg, the default value is `undefined`

Provider/Consumer and class

Instead of creating a context object with createContext(), you can also (1) destructure the context object into a Provider and Consumer, (2) create a class to encapsulate state, and (3) combine Provider and state into a “state provider”.

UserContext.jsx
import React from 'react';

const { Provider, Consumer } = React.createContext();

class UserProvider extends React.Component {
    // encapsulate state in this class
    state = { currentUser: "FAKE_USER" }
    handleLogin() {...}
    handleLogout() {...}

    render() {
        <Provider value={{
            // `UserProvider` combines `Provider` and user state
            // `UserProvider` now can be used to provide user state
            // anywhere in the widget tree where a consumer needs it
            user: this.state.currentUser,
            onLogin: this.handleLogin,
            onLogout: this.handleLogout
            }}
        >
            {this.props.children}
        </Provider>
    }
}

export { UserProvider, Consumer as UserConsumer }

Then use Provider and Consumer:

import { UserProvider, Userconsumer } from './UserContext';

class Root extends React.Component {
    render() {
        <UserProvider>
            <UserConsumer>
            {{ user }} =>
            user ? (
                <MainPage />
            ) : (
                <LoginPage/>
            )
    }
}

2. Provide the context

Provider and context value

To provide the context to all components, have the <CustomContext.Provider /> wrap the top-level component returned by <App />, and pass down whatever you need via value=.

import React from "react";
import MyComponent from "MyComponent";
import ThemeContext from "ThemeContext";

class App extends React.Component {
	render() {
		return (
			<ThemeContext.Provider value="dark">
				<MyComponent />
			</ThemeContext.Provider>
		);
	}
}

Provider and context object

Instead of passing in a context value, you can also pass in a context object with values and callbacks:

render() {
    return (
        <UserContext.Provider
            value={{
                user: this.state.currentUser,
                onLogin: this.handleLogin, // pass in method as callback
                onLogout: this.handleLogout
            }}
    )
}

3. Consume the context

Static property contextType

Add the static property contextType to a class component nested anywhere within the above top-level component. The contextType property makes the context available to the nested component via this.context (magical name by convention).

import React from "react";
import ThemeContext from "ThemeContext";

class DeeplyNestedComponent extends React.Component {
	static contextType = ThemeContext;

	render() {
		return <Button theme={this.context} />; // `this` because class property
	}
}

Consumer

Instead of using contextType, another option is <Context.Consumer>:

import React from 'react';
import ThemeContext from 'ThemeContext';

class DeeplyNestedComponent extends React.Component {

    <ThemeContext.Consumer>
        {context =>
            render () {
                return <Button theme={context} />; // without `this`
            }
        }
    </ThemeContext.Consumer>
}

If you passed in a context object up at Provider, then destructure it here at Consumer:

class DeeplyNestedComponent extends React.Component {
    <UserContext.Consumer>
        {({ onLogin }) => // destructure context object, pick callback
            render () {
                return <Button login={onLogin} />; // pass in callback
            }
        }
    </UserContext.Consumer>
    }
}

useContext hook

Having created a context…

const ThemeContext = React.createContext();

You can use the useContext hook to get it and destructure it.

const MessageList = () => {
	const Theme = useContext(ThemeContext);
};

Hooks

A hook is a function that lets you use state and lifecycle features in a functional component. Hooks are incompatible with class components.

State hook

Call useState(), passing in an initial state value as an argument, to declare and initialize a state value and to create a state value setter. (Declaration, initialization and create only occur on first render; on subsequent renders, the state value and state value setter are read.)

useState() returns an array containing the current state value and a function that updates it. Destructure the array into something (current state value) and setSomething (setter function for that state value).

const [count, setCount] = useState(0);

To store more than one value in state, call useState() as many times as state values you need. Or you can always store a single object with multiple properties.

const [count, setCount] = useState(0);
const [message, setMessage] = useState("Hello");

const [user, setUser] = useState({
	name: "john",
	age: 20
});

State is only created the first time the component renders. During next renders, useState() returns the current state.

The state value can then be freely used in JSX, without prefixing it with props. or this.state. as a normal variable.

<p>You clicked {count} times.</p>

Example:

import React, { useState } from "react";

const App = () => {
	const [count, setCount] = useState(0);
	// initialize state and create state setter

	onButtonClick = () => {
		setCount(count + 1);
		// call setter
	};

	// call setter on click
	return (
		<div>
			<p>You clicked {count} times.</p>
			<button onClick={this.onButtonClick}>Click me</button>
		</div>
	);
};

Effect hook

An effect is an operation performed after every render, be it the first render (mount) or ensuing renders (update). useEffect() thus combines componentDidMount() and componentDidUpdate().

Instead of thinking in terms of “mount” and “update”, think of it as effects that happen “after render”. useEffect() lets you organize effects by related operations, rather than forcing a split based on lifecycle methods.

The effect hook takes in a function as an argument. The function passed in is the effect.

useEffect(() => {
	document.title = `You clicked ${count} times`;
});

Example:

import React, { useState, useEffect } from "react";

const App = () => {
	const [count, setCount] = useState(0);

	useEffect(() => {
		document.title = `You clicked ${count} times`;
		// update document.title after every render
	});

	return (
		<div>
			<p>You clicked {count} times</p>
			<button onClick={() => setCount(count + 1)}>Click me</button>
		</div>
	);
};

Context hook

To read and write to context through a hook:

const UserContext = createContext(
	[
		{
			name: john,
			age: 20
		}
	],
	obj => obj
);

const DeeplyNestedComponent = () => {
	// read context without drilling down props
	// and obtain setter for context, wherever it lives
	const [user, setUser] = useContext(UserContext);
};

Rules

Only call hooks at the top level. In other words, do not call hooks inside loops, conditions, or nested functions inside the functional component.

// WRONG!
if (name !== "") {
	useEffect(function persistForm() {
		localStorage.setItem("formData", name);
	});
}

Only call hooks from React functions. In other words, Don’t call Hooks from regular JavaScript functions.

Code splitting

Loading only what is essential for what the user is requesting, to reduce app size.

React Loadable: https://github.com/jamiebuilds/react-loadable

Built-in code splitting

Code split files that are >30 kb.

import { lazy, Suspense } from "react";

// dynamic import, separate bundle
const Details = lazy(() => import("./Details"));

const App = () => {
    // ...
    return {
        <div>
            // show fallback while import promise is loading
            <Suspense fallback={<h1>Loading...<h1>}>
                <Details />
            </Suspense>
        </div>
    }
}

At component method level

To import conditionally, use import to return a promise and call this.setState with a function:

chooseLocation = () => {
	import("./Location").then(module =>
		this.setState(() => {
			location: module.default;
		})
	);
};

Instead of passing in an object to this.setState we can pass in a function and reliably get the value of the current state of our component.

submit(){
    this.setState((prevState, props) => {
        return { showForm: !prevState.showForm };
    });
}
class DynamicImport extends React.Component {
    state = {
        component = null;
    }

    componentWillMount() {
        this.props.load().then((module) => this.setState(() => {
                component = module.default;
            }));
    }

    render() {
        return this.props.children(this.state.component);
    }
}

const Settings = (props) => {
    <DynamicImport load={() => import("./Settings");}>
        {(Component) => Component === null
            ? <h1>Loading</h1>
            : <Component {...props}>
        }
    </DynamicImport>
}