Reputation: 131
I'm open to alternative methods of performing the same task.
I'd like to do something along the lines of the following:
Menu Item 1
Menu Item 2
Menu Item 3
Target(Where component is loaded)
Upon clicking on a menu item, render the associated component inside the target. Is there a way to dynamically load a component? I.e.
<{menuItemName} />
My current methodology of doing this is awful, slow, and cumbersome(and doesn't work), and involves
<li onClick=this.setState({menuItem:"MenuItem1"})>Menu Item 1</li>
<li onClick=this.setState({menuItem:"MenuItem2"})>Menu Item 2</li>
<li onClick=this.setState({menuItem:"MenuItem3"})>Menu Item 3</li>
<{this.state.menuItem} />
I know there must be a better method of doing this, but I don't currently have the React vocabulary to find the solution I'm looking for. I also am aware that setting state in the render method is a big no-no, but I'm struggling to find the alternative.
Thanks for your help.
Upvotes: 1
Views: 2498
Reputation: 117
As you suggested you have to store somewhere the selected item; for example in the component's state and then display the corresponding component.
const Component1 = (props) => <div>My component 1</div>;
const Component2 = (props) => <div>My component 2</div>;
const Component3 = (props) => <div>My component 3</div>;
// associate the item id with
// the corresponding component
const components = {
1: <Component1 />,
2: <Component2 />,
3: <Component3 />,
}
class MyApp extends Component {
constructor(props) {
super(props);
this.state = { selectedItem: 1 }
}
handleItemClick(itemId) {
this.setState({ selectedItem: itemId });
}
render() {
return (
<div>
<li onClick={() => this.handleItemClick(1)}>Item 1</li>
<li onClick={() => this.handleItemClick(2)}>Item 2</li>
<li onClick={() => this.handleItemClick(3)}>Item 2</li>
{components[this.state.selectedItem]}
</div>
);
}
}
Alternatively you can store the current selected item in the url using React Router.
Check https://react-router.now.sh/quick-start out.
Upvotes: 1
Reputation: 458
Calling setState in render is wrong, but you are just attaching an event listener. Coming to your issue is a jsx representation which compiles to React.createElement(ReactComponent, {}) where the first argument is a React class (can also be a string for HTML elements). Check the answer on this question React / JSX Dynamic Component Name.
However, to solve your problem you can do something like this
handleEventClick(itemId) {
return () => {
this.setState({
itemId
});
}
}
<li onClick={::this.handleEventClick("itemId")}>Item Name</li>
render() {
const { itemId } = this.state;
let renderComponent;
if (itemId === 'menu1') {
renderComponent = <MenuComponent1 />;
} else if ....other components
return (
...
<li onClick={::this.handleEventClick("itemId")></li>...
{renderComponent}
);
}
Upvotes: 1