Skip to content

Instantly share code, notes, and snippets.

@davelosert
Last active January 16, 2021 10:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davelosert/6aecf4a086b87ca35b4fd8ee91bad71d to your computer and use it in GitHub Desktop.
Save davelosert/6aecf4a086b87ca35b4fd8ee91bad71d to your computer and use it in GitHub Desktop.
Beispiel für Subkomponenten-State
import { Menu } from './Menu';
import { MenuModel } from './MenuModel';
import React from 'react';
export class App extends React.Component<any, IAppState> {
public constructor (props: any) {
super(props);
const mockMenuService: MockMenuService = new MockMenuService();
const menu: MenuModel = mockMenuService.getMenu();
this.state = {
menu,
content: 'Content1'
};
}
public render (): JSX.Element {
return (
<React.Fragment>
<Menu menu={this.state.menu} />
<Content content={this.state.content} />
</React.Fragment>
);
}
}
import { MenuEntry } from './MenuEntry';
import { MenuEntryModel } from './MenuEntryModel';
import { MenuModel } from './MenuModel';
import { ReactElement } from 'react';
interface IMenuProps {
menu: MenuModel;
}
export class Menu extends React.Component<IMenuProps> {
public render (): JSX.Element {
const menuEntriesHtml: JSX.Element[] = this.props.menu.entries.map(
(menuEntry: MenuEntryModel, index: number): ReactElement =>
(<MenuEntry key={index} menuEntry={ menuEntry } />)
);
return (
<div className='menu'>
<div className='menu-entries'>
{ menuEntriesHtml }
</div>
</div>
);
}
}
import { MenuEntryModel } from './MenuEntryModel';
import React from 'react';
interface IMenuEntryProps {
menuEntry: MenuEntryModel;
}
interface MenuEntryState extends MenuEntryModel {
isActive: boolean;
isOpened: boolean;
subEntries: MenuEntryState[];
}
const convertToMenuEntryState = (menuEntry: MenuEntryModel): MenuEntryState => ({
...menuEntry,
isActive: false,
isOpened: false,
subEntries: menuEntry.subEntries.map(convertToMenuEntryState)
});
export class MenuEntry extends React.Component<IMenuEntryProps, MenuEntryState> {
constructor (props: IMenuEntryProps) {
super(props);
this.state = convertToMenuEntryState(props.menuEntry);
this.handleMenuClick = this.handleMenuClick.bind(this);
}
private handleMenuClick (): void {
this.setState((currentState): MenuEntryState => ({
...currentState,
isOpened: !currentState.isOpened
}));
}
private handleSubEntryClick (index: number): void {
this.setState((currentState): MenuEntryState => ({
...currentState,
subEntries: currentState.subEntries.map((subEntry, currentIndex): MenuEntryState => {
if (currentIndex === index) {
return {
...subEntry,
isActive: true
};
}
return subEntry;
})
}));
}
public render (): JSX.Element {
const hasSubEntries: boolean = this.props.menuEntry.subEntries.length > 0;
const subEntries: JSX.Element[] = this.state.subEntries.map((subEntry: MenuEntryState, index: number): JSX.Element => (
<div key={index} className={`menu-sub-entry${this.state.isActive ? 'menu-entry-is-active ' : ''}`}>
<div className='menu-text' onClick={ (): void => this.handleSubEntryClick(index)}>{subEntry.text}</div>
</div>
));
return (
<div className='menu-entry-container' onClick={ this.handleMenuClick }>
<div className={`menu-entry ${this.state.isActive ? 'menu-entry-is-active ' : ''}`}>
<div className='menu-text'>{this.props.menuEntry.text}</div>
</div>
{ hasSubEntries &&
<div className={`menu-sub-entries${this.state.isOpened ? 'show-sub-entries ' : 'hide-sub-entries'}`}>
{subEntries}
</div>
}
</div>
);
}
}
export interface MenuEntryModel {
icon: string;
text: string;
link: string;
subEntries: MenuEntryModel[];
}
import { MenuEntryModel } from './MenuEntryModel';
export interface MenuModel {
logoUrl: string;
entries: MenuEntryModel[];
other: any;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment