I'm fairly new to React and I'd like to build a panel to show Recently Viewed URLs within my web site.
I'm trying to use the createBrowserHistory library to do that from a navigation page. Here is the layout:
└── navigation
├── component1
└── component2
└── component3
I'd like to implement something where if I click on component3, then component1, then component2, it would display something like this:
Recently Visited:
component2
component1
component3
I have a History.js file that consists of only this:
import { createBrowserHistory} from 'history';
export default createBrowserHistory({
})
and from the Navigation.js page, I have something like this:
import history from './path/to/History';
import { useLocation } from 'react-router-dom';
const location = useLocation();
history.push(location)
Now if I do a console.log(history), I just see the current path that I'm on, but not the previous URLs. I was under the impression that history.push() pushes the URL to a stack, but how do I extract the last several URLs that were visited?
You need to add the history as a property into the Router(router provider)
import React from "react";
import ReactDOM from "react-dom";
import { Router } from "react-router";
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
ReactDOM.render(
<Router history={history}>
<App />
</Router>,
node
);
And then your hooks would be work well as your expected
I have observed that suddenly CSS path in my project is changed, I am not sure about the reason whether this is a configuration issue or any other, but because of the path CSS is taking too much time to load.
I have already tried to check imports and everything in the code but it seems proper
Please check the below image for path comparison between the new and the backup folder.
New Path:
Old Path
Note: I need the path to be like old where react convert the css to inline, this runs faster.
Below is how I have imported my custom CSS in index.js:
import * as serviceWorker from './serviceWorker';
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import { render } from 'react-dom';
import App from './App';
import './index.css';
import './utilities/animate.css';
//react and redux related library
import { Provider } from 'react-redux';
import store from './redux/store/index';
class Main extends Component {
render() {
return (
<Route path='/' component={App} />
);
}
}
let rootElement = document.getElementById('app');
render(<Provider store={store}>
<BrowserRouter >
<Main />
</BrowserRouter>
</Provider>, rootElement);
serviceWorker.unregister();
I have run npm update and updated few packages, may be some of the packages were corrupted or outdated. This fixed my issue of performance and CSS loading slow.
I've implemented an App component which contains a Route using React and React router:
import {
BrowserRouter as Router,
Route
} from 'react-router-dom';
import createHeader from './components/header/header';
import createLandingPage from './components/landing-page/landing-page';
import createFooter from './components/footer/footer';
export default React => () => {
const Header = createHeader(React);
const LandingPage = createLandingPage(React);
const Footer = createFooter(React);
return (
<section id="sectionId">
<Header />
<Router>
<Route exact path="/" component={LandingPage} />
</Router>
<Footer />
</section>
);
};
The app itself renders and works properly, as I can go to my browser and see everything as expected.
The problem arises when I try to implement proper testing, which runs in Node.js without a browser:
import test from 'tape';
import dom from 'cheerio';
import React from 'react';
import reactDom from 'react-dom/server';
import { MemoryRouter } from 'react-router';
import createApp from './app';
const render = reactDom.renderToStaticMarkup;
test('App init & render', assert => {
const message = 'It sohuld initialize and render the app.';
const App = createApp(React);
const $ = dom.load(render(
<MemoryRouter>
<App />
</MemoryRouter>
));
const output = $('#jptv').length;
const actual = output > 0;
const expected = true;
assert.equal(actual, expected, message);
assert.end();
});
I used MemoryRouter to wrap my app as indicated in React docs to avoid errors, but with or without it, I have the same error when running the test in the console:
Invariant Violation: Browser history needs a DOM
My guess is that I cannot run a component using BrowserRouter out of the browser, yet I don't understand what would be the proper way to test it, as I don't want to force myself to manipulate the code as to fit the test environment shortcomings.
I've searched the web and look into similar issues, but I cannot find an answer, and the docs offer little if no useful information to deal with this.
Any help will be most appreciated.
Thanks!
I am working on project that will use Reactjs on top off rails application.
So i set up my project following this link
Set up Rails with React and Es6
Everything is working fine but i change my bundle.js to this
require('./main');
Then inside main.js i have this
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route } from 'react-router';
import { browserHistory } from 'react-router';
/*Import Component*/
import NotFound from './components/NotFound';
/*
*
* Routes
*
* */
var routes = (
<Router history={browserHistory}>
<Route path="/" component={NotFound}/>
</Router>
);
ReactDOM.render(routes , document.querySelector('#main'));
So inside my component file (/components/NotFound.js)
I have this
import React from 'react';
var NotFound = React.createClass({
render : function () {
return (
<div>
<h1>Not found</h1>
</div>
)
}
});
export default NotFound;
It can be displayed smoothly but the problem is
when i change some code inside my component file (in this case /components/NotFound.js) then refresh the page.
It took around 3 Seconds for just 1 line of code that i added to my component file.
So this is so painful because it took a huge amount of time just for edit a few line of code.
So anyone know how can i reduce the build time to be less than this?
Thanks a lot!
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;
};
(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.
Updated answer is there is a preact-router package now: https://www.npmjs.com/package/preact-router
import Router from 'preact-router';
import { h } from 'preact';
const Main = () => (
<Router>
<Home path="/" />
<About path="/about" />
<Search path="/search/:query" />
</Router>
);
render(<Main />, document.body);
Found the issue, was a pair of problems with Preact's compatibility with React:
Contexts not handled correctly:
https://github.com/developit/preact/issues/156
props.children not handled correctly:
https://github.com/developit/preact-compat/issues/47#issuecomment-220128365
Here is extend solution for preact-router with hash support.
Works with reload and direct access.
https://www.webpackbin.com/bins/-KvgdLnM5ZoFXJ7d3hWi
import {Router, Link} from 'preact-router';
import {h, render} from 'preact';
import {createHashHistory} from 'history';
[cut]...[/cut]
const App = () => (
<div>
<Header />
<Router history={createHashHistory()}>
<Page1 default path="/" />
<Page2 path="/page2" />
</Router>
</div>
);
render(<App />, document.body);