Вопрос: Как составить компонент грамотно?

Лучший ответ: 1. Статические данные. Зачем они определяются каждый render? Их можно вынести за пределы компонента: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>
2. По какой логике используете ключевые слова const и let? Используйте const для всех переменных которые не переопределяются в коде, а let только для тех, которые переопределяются. Это заметно снижает когнитивную нагрузку с читающего код.
3. Конструкции вроде:let
  isPrev = currPathIndex !== 0,
  isNext = currPathIndex !== paths.length - 1;
часто вызывают проблемы при рефакторинге. Лучше не экономить на спичках и писать ключевые слова для каждой строки:const hasPrev = currPathIndex !== 0;  // (1)
const hasNext = currPathIndex !== paths.length - 1; // (2)
В такой код проще вносить изменения и ему не страшны ошибки вроде пропущенной запятой или точки с запятой вместо запятой, что может сэкономить время.(1), (2) - обратите внимание, что я заменил префикс is на has, что правильней. Для булевых переменных помимо is, можно использовать следующие префиксы is, has, should и подобные. Примеры:isVisible
hasChildren
shouldShowCloseButton
4. Если используете много ключей из state и props можно сделать деструктуризацию:const { isOpen } = this.state;
5. Don't repeat yourself.  Код который вы используете многократно старайтесь выносить в отдельные компоненты:<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} />
6. Зачем тернарки там где лучше подойдет &&?{isOpen && this.renderСloseBtn()} // (1)
{hasPrev && <NavButton prev isVisible={!isOpen} path={prevPath} />}
{hasNext && <NavButton next isVisible={!isOpen} path={nextPath} />}(1) - обратите внимание, что рендер кнопки вынесен в отдельный метод, так она будет создаваться только тогда, когда она нужна. В вашем же коде она определяется даже тогда когда не добавляется на страницу.
Используйте тернарный оператор в render, там где есть альтернативный вариант:{isFetching ? <Preloader /> : <Content data={data} />}
Но не используйте вложенных:{isSignedIn ? isMobile ? <UserMenuMobile /> :  <UserMenuDesktop /> : <MainMenu /> }
Лучше так:{isSignedIn ? this.renderUserMenu() : <MainMenu /> }
где this.renderUserMenu:renderUserMenu() {
  return this.props.isMobile ? <UserMenuMobile /> :  <UserMenuDesktop />;
}
7. Старайтесь не писать избыточных конструкций:class Menu extends Component {
  constructor(props) {
    super(props);
      this.state = {
          isOpen: false,
      };
  }
}
При использовании прессета stage-0, create-react-app, jsfiddle и прочих библиотек/бойлерплейтов/сервисов, использующих плагин babel-plugin-transform-class-properties, достаточно:class Menu extends Component {
  state = {
     isOpen: false,
  };
}

Худший ответ: Как Вы думаете, как бы написал опытный реакт-разработчик...Я конечно таковым ни разу не являюсь, но всё-таки скажу пару слов.проверки через тернарный оператор внутри render?Это окей - conditional rendering.render() {
    const paths = [Из метода render массив paths следует убрать. Может быть, его даже стоит сделать параметром компонента.onClick={ () => {this.setState({isOpen: !this.state.isOpen})} }Следует сделать метод. Создавать при каждом вызове render новый обработчик - само по себе не очень здорово, ну и ещё этот код повторяется дважды.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] в качестве параметров.