App.js
):import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import './App.css';
import Menu from "./components/menu/Menu";
import Home from "./components/pages/home/Home";
import Contacts from "./components/pages/contacts/Contacts";
import About from "./components/pages/about/About";
import Projects from "./components/pages/projects/Projects";
class App extends Component {
render() {
return (
<div className="App">
<Menu/>
<main>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/projects" component={Projects}/>
<Route path="/contacts" component={Contacts}/>
</Switch>
</main>
</div>
);
}
}
export default App;
Menu.js
):import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import './Menu.css';
class Menu extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}
componentWillMount() {
this.props.history.listen(() => {
// view new URL
console.log('New URL', this.props.history.location.pathname);
});
}
render() {
const paths = [
{
title: 'Главная',
link: '/'
},
{
title: 'О нас',
link: '/about'
},
{
title: 'Проекты',
link: '/projects'
},
{
title: 'Контакты',
link: '/contacts'
},
];
let
currPath = this.props.history.location.pathname,
currPathIndex = paths.findIndex(n => n.link === currPath);
let
isPrev = currPathIndex !== 0,
isNext = currPathIndex !== paths.length - 1;
let closeBtn = <Link className="close-btn" onClick={ () => {this.setState({isOpen: !this.state.isOpen})} } style={ this.state.isOpen ? {visibility: 'visible', opacity: '1', zIndex: '2'} : {visibility: 'hidden', opacity: '0'} } to="#"/>;
return (
<div>
<nav>
<a className="menu-btn" onClick={ () => {this.setState({isOpen: !this.state.isOpen})} } style={ this.state.isOpen ? {visibility: 'hidden'} : null}>
<span>Меню</span>
</a>
{ this.state.isOpen ? closeBtn : null }
{isNext ? (
<Link className="next_btn" style={ this.state.isOpen ? {visibility: 'hidden'} : null} to={paths[currPathIndex + 1].link}>
<span>{ paths[currPathIndex + 1].title }</span>
</Link>
) : null}
{isPrev ? (
<Link className="prev_btn" style={ this.state.isOpen ? {visibility: 'hidden'} : null} to={paths[currPathIndex - 1].link}>
<span>{ paths[currPathIndex - 1].title }</span>
</Link>
) : null}
</nav>
<div className="menu_frame" style={ this.state.isOpen ? {opacity: '1', zIndex: '2', transition: 'opacity 750ms ease 0s'} : {opacity: '0', zIndex: '-1', transition: 'all 500ms ease 0s' }}>
menu is opened.
<br/>
<strong>Route is:</strong> <i>{ this.props.history.location.pathname }</i>
</div>
</div>
);
}
}
export default withRouter(Menu);
render() -> return()
?const paths = [ ... ];
class Menu extends Component { ... }
import routes from './routes';
/* ... */
<Switch>
{routes.map(route => (
<Route
exact={route.isExact}
path={route.path}
component={route.component}
/>
)}
</Switch>
let
isPrev = currPathIndex !== 0,
isNext = currPathIndex !== paths.length - 1;
const hasPrev = currPathIndex !== 0; // (1)
const hasNext = currPathIndex !== paths.length - 1; // (2)
isVisible
hasChildren
shouldShowCloseButton
const { isOpen } = this.state;
<Link className="next_btn" style={ this.state.isOpen ? {visibility: 'hidden'} : null} to={paths[currPathIndex + 1].link}>
<span>{ paths[currPathIndex + 1].title }</span>
</Link>
<NavButton prev isVisible={!isOpen} path={prevPath} />
{isOpen && this.renderСloseBtn()} // (1)
{hasPrev && <NavButton prev isVisible={!isOpen} path={prevPath} />}
{hasNext && <NavButton next isVisible={!isOpen} path={nextPath} />}
{isFetching ? <Preloader /> : <Content data={data} />}
{isSignedIn ? isMobile ? <UserMenuMobile /> : <UserMenuDesktop /> : <MainMenu /> }
{isSignedIn ? this.renderUserMenu() : <MainMenu /> }
renderUserMenu() {
return this.props.isMobile ? <UserMenuMobile /> : <UserMenuDesktop />;
}
class Menu extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}
}
class Menu extends Component {
state = {
isOpen: false,
};
}
Как Вы думаете, как бы написал опытный реакт-разработчик...Я конечно таковым ни разу не являюсь, но всё-таки скажу пару слов.
проверки через тернарный оператор внутри render
?
Это окей - conditional rendering.Из метода render массив paths следует убрать. Может быть, его даже стоит сделать параметром компонента.render() { const paths = [
Следует сделать метод. Создавать при каждом вызове render новый обработчик - само по себе не очень здорово, ну и ещё этот код повторяется дважды.onClick={ () => {this.setState({isOpen: !this.state.isOpen})} }
this.props.history.listen(...
Если предполагается, что во время работы приложения экземпляр компонента будет создаваться несколько раз, то при удалении экземпляра надо снимать обработчик, иначе вывод в консоль задвоится (затроится, зачетверится,...). Сделать это несложно - listen возвращает функцию, снимающую обработчик, так что:componentWillMount() {
this.unlisten = this.props.history.listen(...
componentWillUnmount() {
this.unlisten();
<Link className="next_btn"...
<Link className="prev_btn"...
isOpen
и свойства объектов paths[currPathIndex +/- 1]
в качестве параметров.