I have made for me a Tutorial-Project where I collect various React-Examples from easy to difficult. There is a "switch/case" conditional rendering in App.js, where I - depending on the ListBox ItemIndex - load and execute the selected Component.
I am trying to optimize my React code by removing the "switch/case" function and replacing it with a two dimensional array, where the 1st column contains the Component-Name 2nd column the Object. Further I would like to lazy-load the selected components.
Everything seems to work fine, I can also catch the mouse events and also the re-rendering begins but the screen becomes white... no component rendering.
App.js
import SampleList, { sampleArray } from './SampleList';
class App extends React.Component {
constructor(props) {
super(props);
this.selectedIndex = -1;
}
renderSample(index) {
if((index >= 0) && (index < sampleArray.length)) {
return React.createElement(sampleArray[index][1])
} else {
return <h3>Select a Sample</h3>;
}
}
render() {
return (
<header>
<h1>React Tutorial</h1>
<SampleList myClickEvent={ this.ClickEvent.bind(this) }/>
<p />
<div>
<Suspense> /**** HERE WAS MY ISSUE ****/
{ this.renderSample(this.selectedIndex) }
</Suspense>
</div>
</header>
);
}
ClickEvent(index) {
this.selectedIndex = index;
this.forceUpdate();
}
}
SampleList.js
import React from 'react';
const SimpleComponent = React.lazy(() => import('./lessons/SimpleComponent'));
const IntervalTimerFunction = React.lazy(() => import('./lessons/IntervalTimerFunction'));
const sampleArray = [
["Simple Component", SimpleComponent],
["Interval Timer Function", IntervalTimerFunction]
];
class SampleList extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.selectOptions = sampleArray.map((Sample, Index) =>
<option>{ Sample[0] }</option>
);
}
render() {
return (
<select ref={this.myRef} Size="8" onClick={this.selectEvent.bind(this)}>
{ this.selectOptions }
</select>
);
}
selectEvent() {
this.props.myClickEvent(this.myRef.current.selectedIndex);
}
}
export default SampleList;
export { sampleArray };
You have several issues in that code:
React.lazy to import components dynamically, use Suspense to show a fallback;select can listen to the change event, and receive the value of the selected option, that is convenient to pass the index in your case;setState with the selected index;
import React, { Suspense, useState, useMemo } from 'react';
const SimpleComponent = React.lazy(() => import('./lessons/SimpleComponent'));
const IntervalTimerFunction = React.lazy(() =>
import('./lessons/IntervalTimerFunction'));
const sampleArray = [
['Simple Component', SimpleComponent],
['Interval Timer Function', IntervalTimerFunction],
];
export default function App() {
const [idx, setIdx] = useState(0);
const SelectedSample = useMemo(() => sampleArray[idx][1], [idx]);
const handleSelect = (idx) => setIdx(idx);
return (
<Suspense fallback={() => <>Loading...</>}>
<SampleList handleSelect={handleSelect} />
<SelectedSample />
</Suspense>
);
}
class SampleList extends React.Component {
constructor(props) {
super(props);
}
selectEvent(e) {
this.props.handleSelect(e.target.value);
}
render() {
return (
<select ref={this.myRef} Size="8" onChange={this.selectEvent.bind(this)}>
{sampleArray.map((sample, idx) => (
<option value={idx}>{sample[0]}</option>
))}
</select>
);
}
}
Working example HERE