Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update dependencies and other fixes #37

Open
wants to merge 19 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
{
"presets": [
["es2015", { "loose": true }],
"react"
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"transform-class-properties",
"transform-export-extensions"
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-export-default-from"
],
"env": {
"test": {
"plugins": [
"transform-async-to-generator",
"transform-object-rest-spread"
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-transform-async-to-generator",
[
"@babel/plugin-transform-runtime",
{
"regenerator": true
}
]
]
}
}
Expand Down
5 changes: 1 addition & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
language: node_js
node_js:
- "4"
- "5"
- "6"
- "7"
- "12"
branches:
only:
- master
Expand Down
55 changes: 55 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,58 @@
## v2.2.0

## NEW - Array Routes

Credit to [@paulcoyle](https://github.com/paulcoyle).

Sometimes you want some routes to take precedence over others. For example,
consider a `/users/invite` route and a `/users/:id` route. JavaScript objects
don't guarantee order, so the `/users/:id` route could take precedence and match
`/users/invite`. So, the `newUser` handler would never run.

## Miscellaneous Changes

* Support redux-saga 0.16 in `peerDependencies`.
* Update README to show React Router v4 support. (credit [@visusnet ](https://github.com/visusnet))

```js
// Can't guarantee precedence with an object
const routes = {
'/users/invite': inviteUser,
'/users/:id': newUser,
};
```

To fix this problem, you can define routes with an array of route objects like
so.

```js
const routes = [
{ pattern: '/users/invite', handler: inviteUser },
{ pattern: '/users/:id', handler: newUser },
];
```

The array form will register routes in the order you provide, ensuring
precedence.

---

## v2.1.2

### Bug Fixes

* Prevent missing `PropTypes` with `createLink` when using React 16. Attempt to import `PropTypes` from the `prop-types` package if `PropTypes` is missing from the `React` object.

---

## v2.1.1

### Internal fixes

* Replace `[...effects]` with `all` per redux-saga 0.15's deprecation notice

---

## v2.1.0

### NEW
Expand Down
107 changes: 83 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ dispatch Redux actions in response to route changes.
- [Install](#install)
- [Usage](#usage)
- [Behavior](#behavior)
- [Parameters](#parameters)
- [Route Matching](#route-matching)
- [Routes](#routes)
- [Options](#options)
- [Navigation](#navigation)
- [Hash History](#hash-history)
- [Browser History](#browser-history)
- [Browser History with React](#browser-history-with-react)
- [React Router v2/v3](#react-router)
- [React Router](#react-router)

## Install

Expand Down Expand Up @@ -103,7 +102,35 @@ your application will continue to function when you hit other routes. That also
means you should ensure you handle any potential errors that could occur in your
route sagas.

## Parameters
## Routes

Routes may be expressed as either an object or an array with the main difference
being that the array form preserves order and, therefore, the precedence of
routes.

```js
const objectFormRoutes = {
'/foo': fooHandler,
'/bar': barHandler,
};

const arrayFormRoutes = [
{ pattern: '/foo', handler: fooHandler },
{ pattern: '/bar', handler: barHandler },
];
```

### Exact Matching

This route will only match `/foo` exactly.

```js
const routes = {
'/foo': saga,
};
```

### Path Parameters

You can capture dynamic path parameters by prepending them with the `:` symbol.
The name you use will be assigned to a property of the same name on a parameters
Expand All @@ -125,22 +152,6 @@ const routes = {
};
```

## Route Matching

Here are some examples of how route matching works.

### Exact Matching

This route will only match `/foo` exactly.

```js
const routes = {
'/foo': saga,
};
```

### Path Parameters

If you specify a dynamic path parameter, then it will be required. This route
will match `/bar/42` but NOT `/bar`.

Expand Down Expand Up @@ -184,6 +195,34 @@ const routes = {
};
```

### Route Precedence

Sometimes you want some routes to take precedence over others. For example,
consider a `/users/invite` route and a `/users/:id` route. JavaScript objects
don't guarantee order, so the `/users/:id` route could take precedence and match
`/users/invite`. So, the `newUser` handler would never run.

```js
// Can't guarantee precedence with an object
const routes = {
'/users/invite': inviteUser,
'/users/:id': newUser,
};
```

To fix this problem, you can define routes with an array of route objects like
so.

```js
const routes = [
{ pattern: '/users/invite', handler: inviteUser },
{ pattern: '/users/:id', handler: newUser },
];
```

The array form will register routes in the order you provide, ensuring
precedence.

## Options

As mentioned earlier, the `router` saga may also take a third argument, an
Expand Down Expand Up @@ -285,12 +324,19 @@ available in React Router. Just pass in your `history` object to the
separate file in your application for exporting your `history` object and your
`Link` component.

If you are also using React Router, you can use the `Link` component that is shipped with React Router.

```js
// history.js

import { createBrowserHistory } from 'redux-saga-router';
import { createLink } from 'redux-saga-router/react'

// Without React Router v4:
import { createBrowserHistory } from 'redux-saga-router';

// With the history npm package:
import createBrowserHistory from 'history/createBrowserHistory';

const history = createBrowserHistory();

export const Link = createLink(history);
Expand Down Expand Up @@ -336,16 +382,22 @@ export default function App() {

### React Router

Redux Saga Router can also work in tandem with React Router v2 or v3! Instead of
Redux Saga Router can also work in tandem with React Router (v2, v3, and v4)! Instead of
using one of Redux Saga Router's history creation functions, just use your
history object from React Router.
history object from React Router (v2, v3) or use the history creation functions provided by the history npm package (v4).

```js
// saga.js

import { router } from 'redux-saga-router';

// React Router v2 and v3:
import { browserHistory as history } from 'react-router';

// React Router v4:
import createBrowserHistory from 'history/createBrowserHistory';
const history = createBrowserHistory();

const routes = {
// ...
};
Expand Down Expand Up @@ -388,12 +440,19 @@ import React from 'react';
import { render } from 'react-dom';
import { applyMiddleware, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { Router, Route, browserHistory as history } from 'react-router';
import App from './App';
import Users from './Users';
import User from './User';
import mainSaga from './saga';

// React Router v2 and v3:
import { Router, Route, browserHistory as history } from 'react-router';

// React Router v4:
import createBrowserHistory from 'history/createBrowserHistory';
import { Router, Route } from 'react-router';
const history = createBrowserHistory();

function reducer() {
return {};
}
Expand Down
51 changes: 50 additions & 1 deletion __tests__/buildRouteMatcher.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import buildRouteMatcher from '../src/buildRouteMatcher';

test('creates a route matcher', () => {
test('creates a route matcher by object syntax', () => {
const rootRoute = () => 'root route';
const fooRoute = () => 'foo route';

Expand All @@ -19,6 +19,55 @@ test('creates a route matcher', () => {
expect(fooMatch.action).toBe(fooRoute);
});

test('creates a route matcher by array syntax, honouring route order', () => {
const fooRoute = () => 'foo route';
const fooBarRoute = () => 'foo bar route';

const descendingSpecificityMatcher = buildRouteMatcher([
{ pattern: '/foo/bar', handler: fooBarRoute },
{ pattern: '/foo/:arg', handler: fooRoute },
]);
const ascendingSpecificityMatcher = buildRouteMatcher([
{ pattern: '/foo/:arg', handler: fooRoute },
{ pattern: '/foo/bar', handler: fooBarRoute },
]);

const descendingFooMatch = descendingSpecificityMatcher.match('/foo/baz');
const descendingFooBarMatch = descendingSpecificityMatcher.match('/foo/bar');
const ascendingFooMatch = ascendingSpecificityMatcher.match('/foo/baz');
const ascendingFooBarMatch = ascendingSpecificityMatcher.match('/foo/bar');

expect(descendingFooMatch).not.toBe(null);
expect(descendingFooBarMatch).not.toBe(null);
expect(ascendingFooMatch).not.toBe(null);
expect(ascendingFooBarMatch).not.toBe(null);

expect(descendingFooMatch.action).toBe(fooRoute);
expect(descendingFooBarMatch.action).toBe(fooBarRoute);
expect(ascendingFooMatch.action).toBe(fooRoute);
expect(ascendingFooBarMatch.action).toBe(fooRoute);
expect(ascendingFooMatch.params.arg).toBe('baz');
expect(ascendingFooBarMatch.params.arg).toBe('bar');
});

test('throws an error when given incompatible values for routes', () => {
expect(() => {
buildRouteMatcher(null);
}).toThrow();

expect(() => {
buildRouteMatcher(undefined);
}).toThrow();

expect(() => {
buildRouteMatcher('string');
}).toThrow();

expect(() => {
buildRouteMatcher(1234);
}).toThrow();
});

test('recognizes fall-through pattern', () => {
const rootRoute = () => 'root route';
const fooRoute = () => 'foo route';
Expand Down
Loading