React router v6 preview

#Navigating with React Router

React Router comes with a component that lets you navigate around your application. If you want to add some styles, has another special called , which accepts styling props. For instance, the property lets us apply a style on the active state.


In our example, we can wrap with a new container component so as to dynamically change the URL.

Copy

importReactfrom’react’

import{NavLink}from’react-router-dom’

constFilterLink=({ filter, children })=>(

<NavLink

exact

to={filter ===’SHOW_ALL’?’/’`${filter}`}

activeStyle={{

textDecoration’none’,

color’black’

}}

>

{children}

<NavLink>

)

exportdefaultFilterLink

Copy

importReactfrom’react’

importFilterLinkfrom’../containers/FilterLink’

import{VisibilityFilters}from’../actions’

constFooter=()=>(

<p>

Show<FilterLink filter={VisibilityFilters.SHOW_ALL}>All<FilterLink>

{‘, ‘}

<FilterLink filter={VisibilityFilters.SHOW_ACTIVE}>Active<FilterLink>

{‘, ‘}

<FilterLink filter={VisibilityFilters.SHOW_COMPLETED}>Completed<FilterLink>

<p>

)

exportdefaultFooter

Now if you click on you will see that your URL will change between , , and . Even if you are going back with your browser, it will use your browser’s history and effectively go to your previous URL.

#Configuring the Fallback URL

Before integrating React Router, we need to configure our development server. Indeed, our development server may be unaware of the declared routes in React Router configuration. For example, if you access and refresh, your development server needs to be instructed to serve because it is a single-page app. Here’s how to enable this with popular development servers.

Configuring Express

If you are serving your from Express:

Copy

app.get(‘/*’,(req, res)=>{

res.sendFile(path.join(__dirname,’index.html’))

})

Configuring WebpackDevServer

If you are serving your from WebpackDevServer: You can add to your webpack.config.dev.js:

Copy

devServer{

historyApiFallbacktrue

}

Meet React Router 5.1

Easily the most notable feature in this release is the addition of some hooks (for React 16.8 users, ofc). We are excited about the ability that hooks give us to compose state and behavior instead of just composing elements.


At its heart, React Router is a state container for the current , or URL. It keeps track of the and renders different s as it changes, and it also gives you tools to update the using s and the API. Given the fact that managing this piece of state is the router’s main responsibility, you can imagine that a new primitive that lets us compose state is going to enable a few things we couldn’t do before!

Let’s explore the new hooks 1 by 1, and we’ll follow it up with some tips about how to get the most out of this release while getting ready for the future of React Router.

First up is . In React Router, we use the word «params» to describe dynamic segments of the URL. Before now, if you wanted to access the current params, you had to get them either through the prop passed to your or through the arguments to our prop, like this:

Both of these methods are fine for getting the current URL params, but they both leave something to be desired. In the case of the prop, the router actually has to for you, which prevents you from passing in custom props to your element. In the case of the prop, you can pass in custom props but you’re forced to manually pass along the values you get from the callback to your element.

In addition, both methods only provide access to the params in , so you’re forced to manually pass them along to components further down the tree if you need them.

Let’s see how fixes all of these problems for us:

Notice 2 things:

  • We don’t have to do any weird component composition tricks to get the params, we can just use regular elements
  • We can anywhere in or its subtree without manually passing params around

There is also another really nice benefit here for TypeScript users: no more typing and/or props! You already know how to type regular React .

Of course, these are really just benefits of using hooks, so they’ll apply to all of the hooks we discuss here. But it’s really interesting to see the practical benefits of hooks in action (we are a training company after all, so we kind of nerd out on this stuff )!

Another hook in the 5.1 release is , which returns the current object. This is useful any time you need to know the current URL.

For example, imagine a hook where you want to send a «page view» event to your web analytics service every time the URL changes. With , it’s as easy as:

For programmatic navigation purposes, we provide access to the object via .

Heads up: The hook is a quick stopgap for a future hook that we are working on: . will provide an API that is more closely aligned with and will fix a few long-standing problems with using the API directly in the router (it’ll probably look a lot like @reach/router’s API). We are providing for now to make the migration of existing code that uses the API as painless as possible.

The hook is useful any time you are using a just so you can get access to its data, including all of the times you might render a all by itself outside of a . It matches the URL exactly like a would, including the , , and options.

So instead of rendering a , just instead:

Just like , if you omit the this hook will return the from the closest matching in the tree.

Object-based Routes

Up to this point we’ve talked about the new , , and APIs which use React elements to declare your routes. I call this API «the JSX API» for routing with React Router.

But React Router v6 ships with another API for routing that uses plan JavaScript objects to declare your routes. In fact, if you look at , you’ll see that it’s really just a tiny wrapper around a hook that is at the heart of the router’s matching algorithm: .

The hook is a first-class API for routing that lets you declare and compose your routes using JavaScript objects instead of React elements. Continuing with the example above, let’s see what it looks like with .

The hook accepts a (possibly nested) array of JavaScript objects that represent the available routes in your app. Each route has a , , and (optionally) , which is just another array of routes.

The object-based route configuration may look familiar if you were using the package in v5. In v6, this configuration format has been promoted to a first-class API in core and the package will be deprecated.

Understanding and Using Links in React Router 5

Links are React Router v5 components designed as a replacment of anchor links to create navigation elements which enable users to navigate between differenet pages of React apps. Unlike anchors ,which reloads the whole page, Links only reload the portion(s) of the UI that match(s) the browser’s location path.

A Link component takes a to property which tells React Router the destination to navigate to. For example:

When clicked will take us to location with path: /

the to prop can either take a string or a location (pathname, hash, search, and state) object, for example:

Link can take also another property: replace if True, when clicked the link entry will be replaced in the history.

Tutorial

Let’s take a look at a simple example.

importReactfrom'react'importReactDOMfrom'react-dom'import{createStore,combineReducers}from'redux'import{Provider}from'react-redux'import{Router,Route,browserHistory}from'react-router'import{syncHistoryWithStore,routerReducer}from'react-router-redux'importreducersfrom'<project-path>/reducers'conststore=createStore(combineReducers({...reducers,    routing routerReducer}))consthistory=syncHistoryWithStore(browserHistory, store)ReactDOM.render(<Provider store={store}>{}<Router history={history}><Route path="" component={App}><Route path="foo" component={Foo}><Route path="bar" component={Bar}><Route><Router><Provider>,document.getElementById('mount'))

Now any time you navigate, which can come from pressing browser buttons or navigating in your application code, the enhanced history will first pass the new location through the Redux store and then on to React Router to update the component tree. If you time travel, it will also pass the new state to React Router to update the component tree again.


Simply listen to the enhanced history via . This takes in a function that will receive a any time the store updates. This includes any time travel activity performed on the store.

consthistory=syncHistoryWithStore(browserHistory, store)history.listen(location=>analyticsService.track(location.pathname))

For other kinds of events in your system, you can use middleware on your Redux store like normal to watch any action that is dispatched to the store.

When using a wrapper for your store’s state, such as Immutable.js, you will need to change two things from the standard setup:

  1. By default, the library expects to find the history state at . If your wrapper prevents accessing properties directly, or you want to put the routing state elsewhere, pass a selector function to access the historystate via the option on .
  2. Provide your own reducer function that will receive actions of type and return the payload merged into the property of the routing state. For example, .

These two hooks will allow you to store the state that this library uses in whatever format or wrapper you would like.

functionmapStateToProps(state,ownProps){return{    idownProps.params.id,    filterownProps.location.query.filter};}

You should not read the location state directly from the Redux store. This is because React Router operates asynchronously (to handle things such as dynamically-loaded components) and your component tree may not yet be updated in sync with your Redux state. You should rely on the props passed by React Router, as they are only updated after it has processed all asynchronous code.

React Router provides singleton versions of history ( and ) that you can import and use from anywhere in your application. However, if you prefer Redux style actions, the library also provides a set of action creators and a middleware to capture them and redirect them to your history instance.

import{createStore,combineReducers,applyMiddleware}from'redux';import{routerMiddleware,push}from'react-router-redux'constmiddleware=routerMiddleware(browserHistory)conststore=createStore(  reducers,applyMiddleware(middleware))store.dispatch(push('/foo'))

Вариант 2. withRouter

В react-router-dom есть встроенная возможность с помощь HOC передать историю в компонент для этого мы сделаем следующие:

// Импорт
import { withRouter } from 'react-router-dom'

Для type scripy

import { withRouter, RouteComponentProps } from 'react-router-dom'

type Props = { ...ваши типы } & RouteComponentProps 

Далее мы обернём импорт компонента в whitRouter

export default whithRouter(CustomComponent)

Чтобы использовать историю мы внутри компонента получим её из пропсов.

const { match, history } = props

А далее нам доступны методы истории, которые описаны в документации. Во простой пример:

history.push('/singin')

whithRourer и connect из react-redux

Не совсем понятно или красиво как использовать whitRouter и conneсt вместе. Для более красивой записи можно использовать lodash/fp. C лодашем запись импорта будет выглядеть так:

import React from 'react'
import fp from 'lodash/fp'
import { connect } from 'react-redux'
import { withRouter }

class CustomComponent extends React.Component{
  .....
}

const mapStateToProps = { ... }
const matDispantToProps = { ... }

export default fp.flow(
  withRouter,
  connect(mapStateToProps, matDispantToProps)
)(Approval)

AuthenticatedComponent¶

Начнем с размышлений и псевдокода:

Закрытыйкомпонент.js_

Что ж, выглядит «заумно»? На деле — воспользуемся старой доброй возможностью прокидывать аргументы в функцию. А так же, сразу сделаем нашу обертку «приконекченной» (connect).

src/containers/AuthenticatedComponent/index.js

В методе мы проверяем — есть ли у user право видеть данный компонент, и если да — показываем. Если нет — .

Обновим роуты:

src/routes.js

Опять же, почувствуйте все удобства «оборачивания»: нам вообще не нужно ничего делать с компонентом .

Перекур. Интересный момент. На дворе 22.04.2016 и мой хром версии — 50.0.2661.75 (64-bit) + React dev tools последней версии.

Давайте проверим как работает наш подход. Зайдите на , залогиньтесь и после редиректа посмотрите в инспектор:

Выглядит не так, как мы ожидали. Вероятно, должно было быть так:


Но у нас:

До текущего момента мы сделали очень много работы, чтобы все работало так как мы ожидаем, не так ли? Если мы пишем — у нас возникает один (камень в огород Angular), если мы хотим чтобы «роутинг» был частью потока данных — мы и это делаем в соответствии с документацией. Тогда в чем дело?

Посмотрите внимательно на код . У нас и аргумент функции и класс наследует . Вероятно, проблема здесь. Давайте просто импортируем чуть-чуть иначе, а название аргумента сохраним.

src/containers/AuthenticatedComponent/index.js

Проверим:

Ожидаемо и предсказуемо. Перекур завершен.

P.S. было «extends Component», стало «extends React.Component» (конечно, строка импорта тоже изменилась)

Understanding React Router 5 Inclusive Routing

In our example app we used the prop exact in the Route for component HomePage

That’s because React Router v5 uses inclusive routing instead of exclusive routing used by React Router v3 so without exact property the home component will be rendered with all other components, for example when the user visits path both and paths will be matched and their corresponding components and will be rendered. But that’s not the behavior we are looking for, that’s why we need to add the exact prop which tells the Route component to match exactly the path.

Now let’s see how we can use inclusive routing in our advantage, lets suppose we have a sub-menu component that needs to be available only when we are on the profile page We can easily change our basic layout to add this requirment:

So as you can see all Routes with path ‘/me’ will be rendered when we visit ‘/me’ path not just the first match, that’s inclusive routing.

How to Help

Probably the best thing you can do to help us get v6 across the finish line is to use it and let us know what you think! You can find instructions about how to get started in the Getting Started guide.

If you already have an app on v5, you can follow the guidelines in the migration guide and let us know what snags you run into. Although there are a few breaking changes from v4/5, we did not lose any functionality, only gained some. So everything you were doing before is possible in the new architecture, and quite a few things should be easier!

One of the other major ways you can contribute to the project is through documentation. Good docs are absolutely essential to the success of any open source project. There are a few different ways you can help us with our docs:

  • Read through the current docs and tell us if something doesn’t flow, there’s a typo, or something is unclear
  • Look for TODOs and submit a pull request (PR)

If you’re interested in submitting a PR, please read through the contributing guidelines first. They’ll help you get all setup.

Hopefully this post has given you some insight into the new features of React Router v6 and what we’re hoping to accomplish with it. I hope it has also given you some ideas about how you can get started with it and use it in your app if you’d like.

We have already started building everything that we do on top of v6 and we have received very positive feedback from several early alpha testers. It shouldn’t be too long before we get a final release out the door.

Enjoy, and we’ll post more updates soon!

Conclusion

React Router v5 makes it dead easy to create React apps with complex UIs that has routing between different portions, you can simply declare a Router component such as BrowserRouter or HashRouter and put,inside of that, a bunch of child Routes components that has props which indicate the path to be matched and the component to be rendered inclusively whenever there is a match (i.e all matched Routes will be rendered). In case you need to do exclusive rendering (Just like React Router v3: i.e only the first matched Route will rendered) then you can simply use a Switch component where only one child (the first found) will be rendered. You can also pass different information between routes using parameters that can be captured and retrieved from the match object which gets created once a match is established and then passed to the current rendered component. Finally all building blocks or components of React Router v5 designed for web apps routing are available and can be imported from react-router-dom.

CacheRoute props

name type default description
when Decide when to cache
className prop for the wrapper component
behavior Return effective on the wrapper component to control rendering behavior
cacheKey For imperative control caching
multiple (React v16.2+) Allows different caches to be distinguished by dynamic routing parameters. When the value is a number, it indicates the maximum number of caches. When the maximum value is exceeded, the oldest updated cache will be cleared.
unmount (UNSTABLE) Whether to unmount the real dom node after cached, to save performance (Will cause losing the scroll position after recovered, fixed with props)
saveScrollPosition (UNSTABLE) Save scroll position

is only a wrapper component that works based on the property of , and does not affect the functionality of itself.

The following values can be taken when the type is

  • Cache when forward behavior occurs, corresponding to the or action in react-router
  • Cache when back behavior occurs, corresponding to the action in react-router
  • Always cache routes when leave, no matter forward or backward

When the type is , the component’s will be accepted as the first argument, return to determine whether to cache.

Introducing

One of the most exciting changes in v6 is the powerful new element. This is a pretty significant upgrade from v5’s element with some important new features including relative routing and linking, automatic route ranking, and nested routes and layouts.

Relative and

Unlike the API in v5, all and values under v6’s element are automatically relative to the parent route that rendered them. This makes it a lot easier to think about your React Router app as lots of small apps that are just stitched together at different «mount» points.

Pulling an example straight from , a v6 app might look something like this:

This example probably looks like no big deal if you’re learning about React Router for the first time. It all seems very intuitive! But if you’re used to how things work in v5, you’ll notice we fixed a few things:

  • You don’t need to use an prop on anymore. This is because all paths match exactly by default. If you want to match more of the URL because you have child routes (see the defined in the component above), use a trailing as in .
  • All routes and links automatically build upon the of the route that rendered them, so e.g. a that is rendered inside a is going to link to .

If you were doing relative routing and linking in React Router v5, you’ll notice you don’t need to manually interpolate and anymore.

Nested Routes and Layouts

In a large app it’s nice to be able to spread out your route definitions across multiple elements so you can do code splitting more easily. But in a smaller app, or with nested components that are closely related, you may want to just see all of your routes in one place. This can help a lot with code readability.

Let’s continue with the previous code example, except this time we’ll combine all of the routes into a single declaration by taking the routes that were defined in our component and hoisting them up into the . We’ll also use an in where the routes used to be to render the child routes.

If you compare this example with the previous one, you’ll notice a few things:

  • We’re using to specify nested routes! The URL paths nest along with the route elements, so renders .
  • We used an element as a placeholder. An in this case is how the component renders its child routes. So the will render either a or element depending on the current location.

One other small thing you may have noticed is that no longer needs the trailing on the path. When the routes are all defined together, you don’t need it because the router can see all your routes at once.

Note: The ability to nest routes like this was one of our favorite features of React Router v3, but we lost it in v4 when we were more focused on the needs of large apps, like code splitting. Version 6 brings together the best of both worlds. Put all your in one spot, or spread them out across your app as needed. It’s up to you!

Redux и react-router-dom

Теперь нам нужно понимать авторизирован пользователь или нет. Для этого я использую redux. Я создал папку store в корне проекта и в нём папку auth. В папке два файла actions.js и redusers.js

В файле actions.js я создал несколько action creater’ов

export const AUTH_CHANGE_PHONE_TEXT = 'AUTH_CHANGE_PHONE_TEXT';
export const AUTH_CHANGE_PASSWORD_TEXT = 'AUTH_CHANGE_PASSWORD_TEXT';
export const AUTH_CHANGE_VALID_PHONE_TEXT = 'AUTH_CHANGE_VALID_PHONE_TEXT';
export const AUTH_CHANGE_VALID_PASSWORD_TEXT = 'AUTH_CHANGE_VALID_PASSWORD_TEXT';
export const AUTH_SET_IS_AUTH_VALUE = 'AUTH_SET_IS_AUTH_VALUE';

export const setPhoneText = (phone) => ({
    type: AUTH_CHANGE_PHONE_TEXT,
    payload: phone
});
export const setValidPhone = (bool) => ({
    type: AUTH_CHANGE_VALID_PHONE_TEXT,
    payload: bool
});
export const setPasswordText = (password) => ({
    type: AUTH_CHANGE_PASSWORD_TEXT,
    payload: password
});
export const setValidPassword = (bool) => ({
    type: AUTH_CHANGE_VALID_PASSWORD_TEXT,
    payload: bool
});
// Значение которое будет отвечать за то авторизирован пользователь или нет
export const setIsAuthValue = (bool) => ({
    type: AUTH_SET_IS_AUTH_VALUE,
    payload: bool
});

В файле redusers.js

import { 
    AUTH_CHANGE_PHONE_TEXT, 
    AUTH_CHANGE_PASSWORD_TEXT, 
    AUTH_CHANGE_VALID_PHONE_TEXT, 
    AUTH_CHANGE_VALID_PASSWORD_TEXT,
    AUTH_SET_IS_AUTH_VALUE 
} from './actions';


const defaultState = {
    phone: '',
    password: '',
    isValidPhone: false,
    isValidPassword: false,
    isAuthValue: false
}

export const authReduser = ( state = defaultState, action ) => {
    switch( action.type ){
        case AUTH_CHANGE_PHONE_TEXT:
            return { ...state, phone: action.payload }
        case AUTH_CHANGE_PASSWORD_TEXT:
            return { ...state, password: action.payload }
        case AUTH_CHANGE_VALID_PHONE_TEXT: 
            return { ...state, isValidPhone: action.payload }
        case AUTH_CHANGE_VALID_PASSWORD_TEXT:
            return { ...state, isValidPassword: action.payload }
        case AUTH_SET_IS_AUTH_VALUE:
            return { ...state, isAuthValue: action.payload }
        default: return state;
    }
}

В папке store так же создаём файл redusers.js и actions.js. В actions.js ничего не пишем, а в файле redusers.js:

import { combineReducers } from "redux";
import { authReduser } from './auth/redusers';
// Прочие импорты

export default combineReducers({
    auth: authReduser,
    // Прочие reduser
});

Если вам сложно разобраться с redux рекомендую посмотреть курс на youtube от codedojo.

React Router v5 vs React Router v3

Before v5 there was React Router v3, React router v5 is a complete re-write so what’s the difference between these two React routers? here is a summary list of most differences:

  • With React router v5, routing is not centralized anymore instead it becomes a part of the rest of the app layout and UI.
  • Browser specific routing components live in react-router-dom instead of react-router so imports need to be changed to be from react-router-dom package.
  • Introducing new components such as BrowserRouter and HashRouter for specific use cases (see below).
  • No more use of {props.children} for nesting components in v5 React Router.
  • React Router v3 routing rules were exclusive meaning only one route will be matched at one time. For v5, routing rules are inclusive meaning multiple routes can be matched and then rendered.

React-router-dom is the version of React Router v5 designed for web applications, React Router v5 was divided into three packages:

  • react-router: common core components between dom and native versions.
  • react-router-dom: the dom version designed for browsers or web apps.
  • react-router-native: the native version designed for react-native mobile apps.

С этим читают