Когда я впервые реализовал React Router, я был сильно сбит с толку. Я только что научился создавать приложения на React, а незадолго до этого выучил JavaScript. Приложение, которое я создавал, также использовало Redux, React hooks, Rails API, auth и т. Д. Я только изучал все эти технологии. Разработка работающего приложения с интуитивно понятным пользовательским интерфейсом и навигационными ссылками уже была сложной задачей. Затем мне пришлось улучшить мое одностраничное приложение, включив в него URL-пути, соответствующие различным функциям приложения. Для этой задачи я использовал React Router.

Настройка и концепция довольно понятны. Необходимо установить пакеты React Router. Компонент приложение должен быть обернут маршрутизатором. Установка маршрутизатора в корне дерева компонентов позволяет всем остальным компонентам нести некоторую халяву: включая встроенные объекты, такие как history. Для каждого рендеринга компонент может быть вложен в маршрут как опора, а также обычно включает определенный путь (среди других возможных опор), например <Route exact path='/' component={Welcome}/>. Таким образом, когда компонент отображает страницу приветствия в DOM, путь URL-адреса выглядит примерно как http://examplewebsite.com/, и пользователь видит начальную страницу веб-сайта с корневым путем '/' в строке URL-адреса.

Несмотря на простоту понимания сути React Router, он включает в себя сложности, которые требуют понимания после внедрения маршрутизатора. Все эти сложности можно изучить и понять с помощью экспериментов, документации и совместной работы, но я наткнулся на препятствие на раннем этапе своей установки, которое не позволило компонентам, которые можно было бы назвать правнуками, дать желаемые результаты.

Представьте, что у этого приложения есть домашняя страница с объявлениями. На эти списки можно щелкнуть и создать страницу показать для выбранного списка. С этой страницы шоу пользователь может захотеть перейти на страницу профиля плаката или, если вы являетесь автором, перейти на страницу редактирования для списка. Или, в следующем примере, давайте будем простыми: пользователь просто хочет вернуться на предыдущую страницу списков.

React Router позволяет создавать методы рендеринга компонента, чтобы изменение пути URL-адреса могло запускать рендеринг различных компонентов. Используя объект history, который переносится на каждом маршруте, можно вызвать встроенный метод .goBack(), вернуть историю на предыдущий путь URL, отобразить предыдущий компонент, и пользователь вернется на предыдущую страницу, которую они просматривали. Вот очень сокращенный пример кода, иллюстрирующий страницу показать для листинга:

import React from 'react'
import {useSelector} from 'react-redux'
const listingShow = ({history}) => {      //history accepted as prop
  const listingShow = useSelector(state =>
    state.listingReducer.listingShow) //listing extracted from state
  const {subject, location, date} = listingShow.attributes
  const navBack = () => {
    history.goBack()
  }
  return (
    <div className='listing-show'>
      <h1>{subject}</h1>
      Location: {location}<br/>
      Date: {date}<br/>
      <button className='btn' onClick={navBack}>Back</button>
    </div>
  )
}
export default listingShow

Я обнаружил, что, хотя я думал, что все мои маршруты и компоненты настроены правильно, я не мог успешно вернуться на страницу при нажатии кнопки «Назад» на странице показа. Обработчик событий onClick вызывает функцию обратного вызова navBack, которая сама вызывает метод .goBack() у унаследованного объекта history, но я понял, что объект истории недоступен, не найден, не существует!

Я ломал голову, изучал ресурсы, доступные в Интернете, и переоценивал свою кодовую базу и дерево компонентов. Я понял, что в какой-то момент цепочка наследования должна была быть разорвана, разорвана, но, хоть убей, я не мог понять, где. Возможно, это было мое разочарование, вызванное отсутствием фокуса или LASER BRAIN, но я просто не мог найти прямого ответа на свой вопрос в документации, справочных сообщениях или где-либо еще. К счастью, мой друг / наставник Лейзл Самано помог мне понять, где произошла моя ошибка.

Многие или большинство компонентов могут напрямую коррелировать с URL-путем, но приложения React также включают компоненты контейнера, которые могут просто не нуждаться в прямом просмотре пользователем. Это действительно контейнеры, которые содержат другие компоненты для организационных или функциональных целей. Рассмотрим это упрощенное дерево компонентов:

index.js - App.js - Welcome.js
                  |
                  - MainContainer.js - ListingContainer.js
                                     |
                                     - ProfileContainer.js

index.js - это корневой скрипт, прикрепленный к шаблону HTML - путь не требуется. App.js - корневой компонент, отображаемый index.js - путь не нужен. В зависимости от того, вошел ли пользователь в систему, App.js отображает страницу приветствия: Welcome.js - соответствующий путь: '/' - и основной компонент контейнера: MainContainer.js - путь не требуется. При входе в систему MainContainer.js отображает контейнер объявлений: ListingContainer.js - соответствующий путь: '/listings' - и контейнер профилей: ProfileContainer.js - соответствующий путь: '/profiles'. Ниже приведен мой первоначальный мыслительный процесс, переданный в код (сокращенный для демонстрационных целей). Посмотрите, сможете ли вы определить основную ошибку, из-за которой возникла ошибка в моем приложении.

//////////////////////////////index.js//////////////////////////////
 1 import React from 'react'
 2 import ReactDOM from 'react-dom'
 3 import {Provider} from 'react-redux'
 4 import {BrowserRouter as Router} from 'react-router-dom'
 5 import configureStore from './configureStore'
 6 import App from './App'
 7
 8 const store = configureStore() 
 9
10 ReactDOM.render(  
11   <Provider store={store}>    
12     <Router>      
13       <App/>    
14     </Router>  
15   </Provider>,  
16   document.querySelector('#root')
17 )
///////////////////////////////App.js///////////////////////////////
 1 import React, {useEffect} from 'react'
 2 import {useDispatch, useSelector} from 'react-redux'
 3 import {loadProfile} from './actions/currentUserActions'
 4 import {Route, Redirect} from 'react-router-dom'
 5 import Welcome from './components/Welcome'
 6 import MainContainer from './containers/MainContainer' 
 7
 8 const App = () => {  
 9   const dispatch = useDispatch()  
10   const currentUser = useSelector(state =>
11     state.currentUserReducer.currentUser) 
12 
13   useEffect(() => dispatch(loadProfile()), [dispatch])   
14
15   return (    
16     <>      
17       {Object.keys(currentUser).length > 0 ?        
18         <MainContainer/> :          
19           <>            
20             <Route exact path='/' component={Welcome}/>  
21             <Redirect to='/'/>          
22           </>      
23       }    
24     </>  
25   )
26 }
27 
28 export default App
//////////////////////////MainContainer.js//////////////////////////
 1 import React from 'react'
 2 import {Switch, Route, Redirect} from 'react-router-dom'
 3 import ListingsContainer from './ListingsContainer'
 4 import ProfilesContainer from './ProfilesContainer'
 5
 6 const MainContainer = () => {  
 7  
 8   return (    
 9     <>      
10       <Switch>        
11         <Route path='/listings' component={ListingsContainer}/> 
12         <Route path='/profiles' component={ProfilesContainer}/> 
13         <Redirect to='/listings'/>      
14       </Switch>    
15     </>  
16   )
17 } 
export default MainContainer

Вы поймали лох? Это код для App.js. Обратите внимание, что в строке 20 объявлен маршрут для страницы приветствия с соответствующим путем и опорой компонента, но в строке 18 есть просто компонент, который нужно отобразить. Сначала это имело для меня смысл, потому что пользователю никогда не нужно переходить к основному контейнеру по URL-адресу и он никогда не увидит его в явном виде. Однако, если не включать маршрут для основного контейнера, цепочка наследования прерывается, и нижеследующая страница показа списка не имеет ссылки на историю браузера. При этом не работает удобная маленькая кнопка «Назад». Решение этой проблемы настолько простое, что я полностью упустил его из виду:

Можно настроить маршруты для рендеринга компонента без указания пути!

Чтобы объект истории продолжал движение вниз от App.js к MainContainer.js, строка 18 из App.js должна быть: <Route component={MainContainer}/>.

Возможно, это кажется очевидным, но я случайно пропустил это, и это показывает, что у каждой технологии есть небольшие ошибки, которые могут не иметь четкого ответа или объяснения. Как только я исправил эту ошибку, реализовать функции React Router в моем приложении стало намного проще. Когда вы LASER BRAIN какую-нибудь загадку с ошибками, отойдите на время от проблемы, изучите свой код с документацией и попросите совета у коллег. Или отправляйтесь в Гластонбери-Гроув, нырните головой в Черную Ложу, а Боб поднимитесь туда.

Github.com/dangrammer
connected.com/in/danieljromans
danromans.com