TbWill4321 TbWill4321 - 2 months ago 10
React JSX Question

How to use React Router with Preact

I'm using Preact as my View framework (can NOT use React due to the Facebook IP problems). I needed to use React Router for the location routing because it has more flexibility than the Preact Router that the same team built.

I managed to get React Router to accept Preact in place of React, however, I can't get it to match locations. I'm not sure if it's a compatibility problem, or a configuration problem. I've tried using just one pair of routes ( App and Account ) and it still doesn't work with that simplified setup.

Q: Does anyone see if I'm doing something wrong here?

The error I get is:

Location "/account/12345/" did not match any routes


main.js

import { h, render } from 'preact';
import { Router, browserHistory } from 'react-router';
import { Provider } from 'react-redux';

import createStore from './createStore';
import createRoutes from './createRoutes';

process.env.DEBUG && console.log('Hello, developer!');

const history = browserHistory;
const store = createStore( history );
const routes = createRoutes( store );

render((
<Provider store={ store } key="redux-provider">
<Router history={ history } createElement={ h } routes={ routes } />
</Provider>
), document.body );


createRoutes.js

import { h } from 'preact';
import { IndexRoute, Route } from 'react-router';

// App Component
import App from './components/app';

// Sub Components
import Account from './components/account';
import Conversation from './components/conversation';
import Dashboard from './components/dashboard';

// Error Components
import BadAccount from './components/bad-account';
import NotFound from './components/not-found';

// Routes
export default ()=> (
<Route path="/" component={App}>
{/* Get URL parameter */}
<Route path="account/:accountID" component={Account}>
{/* Index Route */}
<IndexRoute component={Dashboard} />
{/* Sub Routes ( Alphabetical Please ) */}
<Route path="chat" component={Conversation} />
{/* Catch-All Route */}
<Route path="*" component={NotFound} />
</Route>
{/* Handle Invalid URIs */}
<Route path="*" component={BadAccount} />
</Route>
);


createStore.js



import { applyMiddleware, combineReducers, compose, createStore } from 'redux';
import thunk from 'redux-thunk';
import { routerMiddleware } from 'react-router-redux';

import messages from './resources/messages/reducer';
import conversation from './resources/conversation/reducer';
import layout from './resources/layout/reducer';
import profile from './resources/profile/reducer';
import contract from './resources/contract/reducer';

/*const { devToolsExtension } = window;*/

export default history => {

// Sync dispatched route actions to the history
const reduxRouterMiddleware = routerMiddleware( history );

// Create single reducer from all modules
const rootReducer = combineReducers({
messages,
conversation,
layout,
profile,
contract
});

// List redux middleware to inject
const middleware = [
thunk,
reduxRouterMiddleware
];

// Compose the createStore function
const createComposedStore = compose(
applyMiddleware( ...middleware )/*, // Figure this out...
( process.env.DEBUG && devToolsExtension ) ? devToolsExtension() : f => f*/
)( createStore );

// Create the store
const store = createComposedStore( rootReducer );

// Hook up Redux Routing middleware
// reduxRouterMiddleware.listenForReplays(store);

// Return store
return store;
};



Answer

(OP already solved his issue, but this ranks high in Google and is not very helpful for newcomers, so I thought I'd provide some background info)

Preact and preact-compat

preact is a minimal version of React that weighs just 3Kb. It implements a subset of React's API, with some small differences here and there. It also comes with a helper library, preact-compat, which provides compatibility with React by filling in missing parts and patching up API differences.

React-Router

react-router is a router library designed to work with React. But you can make it work with Preact as well, using preact-compat.

Setting up preact-compat

npm i --save preact-compat

Make sure you set up aliases for react and react-dom in your webpack / browserify configuration, or write some code to set up these aliases manually.

example webpack config

{
    // ...
    resolve: {
        alias: {
            'react': 'preact-compat',
            'react-dom': 'preact-compat'
        }
    }
    // ...
}

Then you can use React Components as-is. They won't know they are being rendered by Preact i.s.o. React. Have a look at this preact-compat-example.

Issues with compatibility

Keep in mind that when you are using Preact Compat, you are taking a risk. Jason is a very smart guy, but his library is only a fraction of the size of the one provided by Facebook so there's bound to be some differences. Components that use lesser known features of React might not work correctly. If you encounter such issues, report them to the preact-compat issue tracker (with a minimal reproduction in the form of a GitHub repo) to help him improve it.

There have been a few of such issues in the past that prevented React-Router from working correctly with Preact, but they have been fixed since and you should now be able to use the two together nicely.

Fiddle of Preact + React-Router

Have a look at this JS Fiddle for a working example.

Comments