Когда я впервые реализовал 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