26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/TransitionableComponent.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import RouteTransitions from './RouteTransitions'
3 |
4 | export default class TransitionableComponent extends React.PureComponent {
5 | constructor (props) {
6 | super(props)
7 |
8 | this.willAppear = this.willAppear.bind(this)
9 | this.willEnter = this.willEnter.bind(this)
10 | this.willLeave = this.willLeave.bind(this)
11 | }
12 |
13 | componentWillMount () {
14 | this.props.emitter.once(RouteTransitions.WILL_APPEAR, this.willAppear)
15 | this.props.emitter.once(RouteTransitions.WILL_ENTER, this.willEnter)
16 | this.props.emitter.once(RouteTransitions.WILL_LEAVE, this.willLeave)
17 | }
18 |
19 | componentWillUnmount () {
20 | this.props.emitter.removeAllListeners()
21 | }
22 |
23 | willAppear (done) {
24 | done()
25 | }
26 |
27 | willEnter (done) {
28 | done()
29 | }
30 |
31 | willLeave (done) {
32 | done()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "transitionable-routes",
3 | "version": "0.2.0",
4 | "description": "Perform transitions when changing routes with React Router",
5 | "license": "MIT",
6 | "repository": "github:rafaelrinaldi/transitionable-routes",
7 | "main": "dist/transitionableRoutes.umd.js",
8 | "jsnext:main": "dist/transitionableRoutes.es.js",
9 | "module": "dist/transitionableRoutes.es.js",
10 | "keywords": [
11 | "animation",
12 | "animations",
13 | "motion",
14 | "react",
15 | "react-router",
16 | "route",
17 | "router",
18 | "routes",
19 | "transition",
20 | "transitions"
21 | ],
22 | "scripts": {
23 | "build": "rollup -c",
24 | "test": "NODE_ENV=test prettier-standard index.js && jest --verbose",
25 | "start": "NODE_ENV=development parcel examples/index.html -p 8000"
26 | },
27 | "files": [
28 | "dist"
29 | ],
30 | "devDependencies": {
31 | "babel-core": "^6.26.3",
32 | "babel-plugin-external-helpers": "^6.22.0",
33 | "babel-preset-env": "^1.7.0",
34 | "babel-preset-react": "^6.24.1",
35 | "babel-preset-stage-0": "^6.24.1",
36 | "jest-cli": "^23.4.1",
37 | "prettier-standard": "^8.0.1",
38 | "rollup": "^0.63.4",
39 | "rollup-plugin-babel": "^3.0.7",
40 | "rollup-plugin-node-builtins": "^2.1.2"
41 | },
42 | "optionalDependencies": {
43 | "parcel-bundler": "^1.6.2",
44 | "react-dom": "^16.2.0"
45 | },
46 | "dependencies": {
47 | "react": "^16.4.1",
48 | "react-router": "^4.3.1",
49 | "react-router-dom": "^4.3.1"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [animate]: http://animate.mhaagens.me
2 | [events]: https://github.com/Gozala/events
3 | [potato]: https://github.com/codify-to/Potato
4 | [react-router-v4-transition]: https://github.com/aboeglin/react-router-v4-transition
5 | [react-router]: https://reacttraining.com/react-router
6 | [react-transition-group]: https://github.com/reactjs/react-transition-group
7 | [react]: https://reactjs.org
8 | [redux]: https://redux.js.org
9 | [robotlegs]: http://www.robotlegs.org
10 | [url]: https://rinaldi.io
11 |
12 | # transitionable-routes 
13 |
14 | > Perform transitions when changing routes with React Router
15 |
16 | # Install
17 |
18 | ```sh
19 | npm i transitionable-routes
20 | ```
21 |
22 | ## The Problem
23 |
24 | The ability to add animations whenever a route changes seems like such a trivial feature but weirdly enough I haven't found a nice way of doing it with [React][react] and [React Router][react-router].
25 |
26 | All the examples I've seen out there – including the ones in the official docs – usually assume you are performing generic transitions such as fading in and out the routes entering and leaving. If you need more control over that, good luck.
27 |
28 | At some point in time this was achievable via [react-transition-group][react-transition-group] but at some point React Router had a major bump that broke integration with it and as a workaround the react-transition-group team changed the API in a way that for me was a downgrade since they've made much harder to make things customizable (they've added a `in` property that makes no sense to me and instead of controlling animations via callbacks you had to pass down how long transitions would take, which is an idea that I dislike very much).
29 |
30 | Coming from a Flash background I remember this used to be a feature we took for granted. Either you rolled your own at the beginning of the project or you would have it available via frameworks (shout out to [Potato (aka Patota)][potato] and [Robotlegs][robotlegs]).
31 |
32 | ## The Solution
33 |
34 | >Keep in mind that this was put together in a few hours and is still experimental. If you have ideas on how to improve it, do chime in.
35 |
36 | Out of desperation (I couldn't imagine this would take longer than a few minutes to ship) I decided to hack my way into a solution. I have started by writing the API that I wanted then started putting something together off of some good ideas that I've seen in the wild.
37 |
38 | ### `TransitionableSwitch`
39 |
40 | This is a simple stateful React component that acts as a replacement for React Router's `Switch`. It knows how to render route components based on the active route, but it also knows how to coordinate rendering of routes that are transitioning (either entering or leaving).
41 |
42 | This component injects hooks to every route component that is transitioning so inside of it you have access to transition states.
43 |
44 | The coordination of transition states is done via [event emitters][events]. These are responsible for communicating state from the switcher down to the component.
45 | I have tried using React `ref` for this but had a bad experience, specially when you're trying to wrap a [Redux][redux]-connected component, so I went for good ol' event emitters (which still sounds kinda crazy but did the job well).
46 |
47 | ### `TransitionableComponent`
48 |
49 | This is a simple React component that automatically handles syncing the component to the event emitter and exposes all the hooks available for transitions:
50 |
51 | * `willAppear`
52 | * `willEnter`
53 | * `willLeave`
54 |
55 | All hooks receive a callback function as an argument so you can do whatever you want and call them once you're done.
56 |
57 | ## Usage
58 |
59 | ```jsx
60 | import React from 'react'
61 | import { render } from 'react-dom'
62 | import { BrowserRouter, Route } from 'react-router-dom'
63 | import { TransitionableSwitch, TransitionableComponent } from 'transitionable-routes'
64 |
65 | const Home = () =>