Method:
onSearch(searchString) {
if (this.props.history) {
this.props.history.push(
"/details?search=" + encodeURIComponent(searchString)
);
}
}
Search Bar:
<Search
onKeyPress={(event) => {
if (event.key === "Enter") {
this.onSearch(event.target.value);
}
}}
/>
onSearch method opens this url: http://localhost:3000/marketPlace/details?search=iphone and surfacing all the results with "iphone". What I want is whenever user bookmark this url, he should fall back in the same page with the search result as iphone . I have no idea how to do this, can anyone help me with this
Assuming you are writing a client side application and you do not need the search results to be server side rendered, React Router (npm react-router-dom) will enable you to recreate a particular state of your app, based upon the url requested.
You should be able to apply a router to your existing app by following the React Router documentation: https://reacttraining.com/react-router/web/guides/quick-start
Here is a very simple example of a router that is similar to your use case.
The example shows that:
A request to / will render the "Homepage" component.
A request to /search?term=iphone will render the "SearchResults" component and this.searchTerm will be equal to the string iphone.
The SearchResults component parses the query string from the url and identifies the search term. In the example, this is just displayed to the end user, but you can use it to fetch your search results e.g. using fetch().
You can reproduce the example with two files:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Switch,
Route
} from 'react-router-dom';
class SearchResults extends React.Component {
constructor(props) {
super(props);
let queryString = new URLSearchParams(props.location.search);
this.searchTerm = queryString.get('term');
}
render() {
return <p>Search results page for term: { this.searchTerm }</p>;
}
}
function App() {
return (
<Router>
<Switch>
<Route path="/search" component={SearchResults} />
<Route path="/">
<p>Homepage</p>
</Route>
</Switch>
</Router>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>React App</title>
</head>
<body>
<div id="root"></div>
<script src="index.js"></script>
</body>
</html>
Related
I am new to react and i am creating a simple Contact Manager App, i have contacts and addContact components, these are separated in different routes.
When i add a contact,it gets added to the local storage and the contacts component is getting the list of contacts from the local storage.
The problem that when i add a contact and i redirect to the contacts page, the new contact doesn't show unless i manually refresh the page.
i tried this :
this.props.history.push('/');
this too
window.location.href=window.location.hostname;
and i created a function to refresh the page if the previous link is the addContact link, it doesn't work either
this is the App component code:
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Navbar from './components/navbar';
import Contacts from './components/contacts';
import About from './components/pages/about';
import AddContact from './components/pages/addContact'
import NotFound from './components/pages/notFound'
function getContactsLS() {
let contacts;
if (localStorage.getItem('contacts') === null) {
contacts = [];
}
else {
contacts = JSON.parse(localStorage.getItem('contacts'));
}
contacts = Array.from(contacts);
return contacts;
}
class App extends React.Component {
contactsLS = getContactsLS();
render() {
return (
<Router>
<Navbar />
<div className="container">
<Switch>
<Route exact path="/add-contact" component={AddContact} />
<Route exact path="/" component={() => <Contacts contacts={this.contactsLS} />} />
<Route exact path="/about" component={About} />
<Route component={NotFound}/>
</Switch>
</div>
</Router>
)
}
}
export default App
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
this is addContact function :
addContactEvent = () =>{
let contacts;
if(localStorage.getItem('contacts')===null)
contacts=[];
else{
contacts=JSON.parse(localStorage.getItem('contacts'));
}
contacts=Array.from(contacts);
console.log(contacts);
this.setState({key:contacts.length});
const contact = {
key : contacts.length,
name: this.state.name,
email:this.state.email,
phone:this.state.phone
}
contacts.push(contact);
localStorage.setItem('contacts', JSON.stringify(contacts));
//redirection
//this.props.history.push('/');
window.location.href=window.location.hostname;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
It feels like you would want the contacts as part of the state. In that case the code would be:
state = { contactLS: getContactsLS()}
But as we are calling values from localStorage a more appropriate place might be
componentDidMount() method.From react docs
Avoid introducing any side-effects or subscriptions in the
constructor. For those use cases, use componentDidMount() instead.
Then the code would be
componentDidMount(){
const contacts = getContactsLS()
this.setState({ contacsLS: contacts })
}
Don't forget to change to this.state.contactsLS
<Route exact path="/" component={() => <Contacts contacts={this.state.contactsLS} />} />
====
PS
Another problem i can see in the existing code is the misuse of component constructor.
This is not obvious but the line
contactsLS = getContactsLS();
is equivalent to
constrcutor(){
this.contactLS = getContactLS();
}
from react documentation we read
Typically, in React constructors are only used for two purposes:
- Initializing local state by assigning an object to this.state.
- Binding
event handler methods to an instance.
You could use <Redirect> component from react-router-dom package. To get it working you initially setState where redirect is set to false.
this.state = {
redirect: false
}
Once the addContact opeartion is done, update the state
this.setState({
redirect: true
})
Inside of your AddContact component, the state will decide if it has to show the actual component or to redirect to the attached path.
Something like this:
import {Redirect } from 'react-router-dom';
class AddContact extends React.Component {
//Add the initial state
// addContact Operation
render(){
if(this.state.redirect)
return <Redirect to="/" />
return (
//The markup for AddContact
)
}
}
I want to get the location of the page I'm on in order to set up conditional rendering. Originally, I had something set up like this
const currentPath = window.location.pathname;
...
<h1>{currentPath}</h1>
And that would echo out the path as http://example.com/page.
But since I've switched to using HashRouter, and page links are generated like http://example.com/#/page, the only thing that echoes out is "/"
How do I get the location of the page after the hash?
Route in React-router v4 passes three props to the component it renders. One of these is the match object. It contains information about how the current path was matched.
In your case, you can use match.path or match.url to get the location of the page.
Something like this:
import React from 'react';
import { render } from 'react-dom';
import { Route, HashRouter as Router, Switch } from 'react-router-dom';
const Child = ({ match }) => {
return <p>{match.url}</p>;
};
const App = () => (
<Router>
<Switch>
<Route exact path='/' component={Child} />
<Route exact path='/test1' component={Child} />
<Route exact path='/test2' component={Child} />
</Switch>
</Router>
);
render(<App />, document.getElementById('root'));
Working code is available here:
https://codesandbox.io/s/3xj75z41z1
Change the route in the preview section on the right to / or /test1 or /test2, and you'll see the same path displayed on the page.
Hope this helps. Cheers! :)
React Router provides location parameter out of box.
You can access it like location.pathname
For eg: if the component is Page:
const {HashRouter, Route, Link} = ReactRouterDOM;
function Page({location}) {
return <p>{location.pathname}</p>;
}
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<HashRouter>
<div>
<Route path="/page" component={Page} />
<Link to='/page'>Link to Page</Link>
</div>
</HashRouter>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/react-router-dom/umd/react-router.min.js"></script>
<script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script>
<div id="root"></div>
https://reacttraining.com/react-router/web/api/location
I'm building a crypto currency market app as an to practice reactjs. When app starts list of currencies with some properties will be shown as a list. I need to navigate to a different page (new page - Currency component) without loading the component on the bottom of current page. At the moment I was able to render it in the bottom of the page. But that's not what I need.
Is there any other way than which is mentioned in Route to different page[react-router v4] ? Because I need to pass the clicked object (currency) to the new component (Currency)
Here's my CryptoList component currency_main.js
import React, { Component } from 'react';
import {
Table,
TableBody,
TableHeader,
TableHeaderColumn,
TableRow,
TableRowColumn,
} from 'material-ui/Table';
import Currency from './currency';
import {
BrowserRouter as Router,
Link,
Route
} from 'react-router-dom'
class CryptoList extends Component {
constructor(props){
super(props);
this.state = {
currencyList : [],
showCheckboxes : false,
selected : [],
adjustForCheckbox : false
}
};
componentWillMount(){
fetch('/getcurrencylist',
{
headers: {
'Content-Type': 'application/json',
'Accept':'application/json'
},
method: "get",
dataType: 'json',
})
.then((res) => res.json())
.then((data) => {
var currencyList = [];
for(var i=0; i< data.length; i++){
var currency = data[i];
currencyList.push(currency);
}
console.log(currencyList);
this.setState({currencyList})
console.log(this.state.currencyList);
})
.catch(err => console.log(err))
}
render(){
return (
<Router>
<div>
<Table>
<TableHeader
displaySelectAll={this.state.showCheckboxes}
adjustForCheckbox={this.state.showCheckboxes}>
<TableRow>
<TableHeaderColumn>Rank</TableHeaderColumn>
<TableHeaderColumn>Coin</TableHeaderColumn>
<TableHeaderColumn>Price</TableHeaderColumn>
<TableHeaderColumn>Change</TableHeaderColumn>
</TableRow>
</TableHeader>
<TableBody displayRowCheckbox={this.state.showCheckboxes}>
{this.state.currencyList.map( currency => (
<TableRow key={currency.rank}>
<TableRowColumn>{currency.rank}</TableRowColumn>
<TableRowColumn><Link to='/currency'>{currency.name}</Link></TableRowColumn>
<TableRowColumn>{currency.price_btc}</TableRowColumn>
<TableRowColumn>{currency.percent_change_1h}</TableRowColumn>
</TableRow>
))}
</TableBody>
</Table>
<div>
<Route path='/currency' component={Currency} />
</div>
</div>
</Router>
);
}
}
export default CryptoList;
And here's my Currency component currency.js
import React, { Component } from 'react';
class Currency extends Component {
componentWillMount(){
console.log(this.props.params);
}
render(){
return (
<div>
<h3>
This is Currency Page !
</h3>
</div>
);
}
}
export default Currency;
And here's the currency component which I need to render into a new page when I click currency name in the currency_main component (Which is in second <TableRowColumn>).
I'm bit new to react and tried react-router in a tutorial only and it was rendering a page as a part of currenct page only.
So how can I go to a new page using react-router v4 ?
P.S : I've uploaded the image. As an example if click on Ethereum I need to render the Currency component as a new page.
And this should be resulted as the output when I click on Ethereum (as an example) instead of rendering This is Currency Page ! on the same component CryptoList.
You already had the imports in this.
import {
BrowserRouter as Router,
Link,
Route
} from 'react-router-dom'
However, I would remove all of the routings in your CyptoList page and just make that CyptoList a component.
Now, you want to use those Links in your code to navigate between pages you need to make a place that you want to display the links in.
const Header = () => (
<nav>
<ul>
<li><Link to='/'>CryptoList</Link></li>
<li><Link to='/currency'>Currency</Link></li>
</ul>
</nav>
)
If in your CyptoList page you can just put the header in there like this <Header />
Now, the next part, the Router, you might want to make a new Router.js file or separate it. Or you could do something like this.
// Routes.js
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import CryptoList from './CryptoList'; // or whatever the location is
import Currency from './Currency'; // or whatever the location is
export default () => (
<BrowserRouter>
<Switch>
<Route exact path="/" component={CryptoList}/>
<Route path="/currency" component={Currency}/>
</Switch>
</BrowserRouter>
);
Then when you want to include your Routes as you saved it in the Routes.js file you can just do this.
import Routes from './Routes';
and use it by doing this...
<Routes />
You can always refer to this example on medium with a link to a CodeSandbox and CodePen. https://medium.com/#pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf
I encountered the same problem.
Your <Route /> is located in App.js. This is why every time you navigate to currency component you can still see original view in App.js.
Here is the solution:
You just need to move <Route /> to index.js not in App.js. Because in index.js there is nothing. when you navigate to <Currency /> you will go to a completely new page. You will never see views in App.js
I'm trying to incorporate this map into an existing grails/react project.
Updated code:
index.js
ReactDOM.render((
<Router history = {browserHistory}>
<Route path="/" component={CreateAccount}/>
<Route path="/menu" component={Menus}/>
<Route path="/discover" component={DiscoverApp}/>
<Route path="/NorthAmerica" component={northAmerica}/>
<Route path="/SouthAmerica" component={southAmerica}/>
<Route path="/Europe" component={europe}/>
<Route path="/Asia" component={asia}/>
<Route path="/Africa" component={africa}/>
<Route path="/Australia" component={australia}/>
</Router>
), document.getElementById('root'));
index.gsp
<head>
<title>Food App</title>
<link rel="stylesheet" href="${resource(dir: 'css', file: 'text.css')}" type = "text/css">
<link rel="stylesheet" href="${resource(dir: 'css', file: 'jquery-jvectormap-2.0.3.css')}" type = "text/css" media="screen">
<javascript src="/js/jquery-3.1.1.js" />
<javascript src="jquery-jvectormap-2.0.3.min.js" />
<javascript src="jquery-jvectormap-world-mill-en.mins.js" />
</head>
<body>
<div id="root" align="left"></div>
<br/>
<asset:javascript src="bundle.js"/>
</body>
</html>
and
import React, { Component } from 'react';
import {Link} from 'react-router';
import $ from 'jquery';
import ReactDOM from 'react-dom';
class NorthAmerica extends Component {
componentDidMount() {
const el = ReactDOM.findDOMNode(this.display);
$(el).vectorMap({map: 'world_mill_en'});
}
render(){
return(
<div>
<h1>NORTH AMERICA MAP PLACE-HOLDER</h1>
<li><Link to="/discover">DISCOVER</Link></li>
<div
ref={display => this.display = display}
/>
</div>
)
}
}
export class northAmerica extends React.Component{
render(){
return(<NorthAmerica/>);
}
}
Any suggestions? Thanks!
Updated:
Page loads now... but where the map should be is just a blank div. I get this error in the console:
Uncaught TypeError: (0 , _jquery2.default)(...).vectorMap is not a function
at NorthAmerica.componentDidMount (bundle.js?compile=false:12781)
at bundle.js?compile=false:26803
at measureLifeCyclePerf (bundle.js?compile=false:26613)
at bundle.js?compile=false:26802
at CallbackQueue.notifyAll (bundle.js?compile=false:9088)
at ReactReconcileTransaction.close (bundle.js?compile=false:31708)
at ReactReconcileTransaction.closeAll (bundle.js?compile=false:5241)
at ReactReconcileTransaction.perform (bundle.js?compile=false:5188)
at ReactUpdatesFlushTransaction.perform (bundle.js?compile=false:5175)
at ReactUpdatesFlushTransaction.perform (bundle.js?compile=false:1438)
refs in React is required to grab the underlying DOM inside the React component. Once that is available in the component, third party library functions like vectorMap can be called on the jQuery element. Here is an example of the React component assuming all appropriate dependent libraries are available to render DOM.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';
class NorthAmerica extends Component {
componentDidMount() {
const el = ReactDOM.findDOMNode(this.display);
$(el).vectorMap({map: 'world_mill_en'});
}
render() {
return <div>
<h1>World Map</h1>
<div
ref={display => this.display = display}
style={{width: '600px', height: '400px'}}
/>
</div>;
}
}
/*
* Render the above component into the div#app
*/
ReactDOM.render(<NorthAmerica />, document.getElementById('app'));
Here is the example codepen which does not work because I wasn't able to provide an appropriate version of jqueryvectormap library.
An exported and modified version of the above codepen works. git clone then open index.html in browser.
You should use one of React's component lifecycle methods to execute your function rather than trying to render an inline script tag. Try removing the inline script from the render method and adding a componentDidMount method:
componentDidMount() {
$(your jQuery function here);
}
Assuming you're using webpack, you'll probably want to declare jquery as an external, but the above should at least get things up and running.
Instead of:
let NorthAmerica = React.createClass({
You can export this straight away:
export default class NorthAmerica extends React.Component {
and then delete your last code block:
export class northAmerica extends React.Component{
render(){
return(<NorthAmerica/>);
}
}
The reason you can't see anything is because your NorthAmerica component is not added to the DOM yet. Try:
ReactDOM.render(
<NorthAmerica />,
document.getElementById('root')
);
Where 'root' is replaced with the name of a div in your index.gsp which is the container for all react content, refer to enter link description here
For this to work you will need an extra import:
import ReactDOM from 'react-dom';
Export is only required if you are using NorthAmerica from another file. If you are not doing that yet then it is not required, see here
Resume: I need to run React Router without wepback or similar tools. Directly from CDN links, but I'm stuck with some require.js error.
I'm starting to build my first App with React and I'm struggling with React Router.
HTML:
<body>
<div id="container"></div>
<script src="https://unpkg.com/react#15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#15/dist/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.js"></script>
<script src="https://npmcdn.com/react-router#2.4.0/umd/ReactRouter.js"></script>
<script type="text/babel" src="assets/scripts/03_templates/app.js" charset="utf-8"></script>
</body>
JS:
var { Router, Route, IndexRoute, hashHistory, IndexLink, Link, browserHistory } = ReactRouter;
//some classes
ReactDOM.render((
<Router history={hashHistory}>
<Route path="/" component={Window}>
<IndexRoute component={InitialPage}/>
<Route path="register" component={Register} />
<Route path="search" component={Search} />
</Route>
</Router>
), document.getElementById("container"));
Everything is running fine but i get this on console:
react.js:3639 Warning: You are manually calling a React.PropTypes
validation function for the getComponent prop on IndexRoute. This
is deprecated and will not work in production with the next major
version. You may be seeing this warning due to a third-party PropTypes
library.
So, I suppose my react Router is a old version. I changed the link to
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router/4.0.0-0/react-router.js"></script>
Warning: React.createElement: type should not be null, undefined,
boolean, or number. It should be a string (for DOM elements) or a
ReactClass (for composite components).
I search about it and it seems the problem is on line 1. So I changed this:
var { Router, Route, IndexRoute, hashHistory, IndexLink, Link, browserHistory } = ReactRouter;
To this:
import { Router, Route, IndexRoute, hashHistory, IndexLink, Link, browserHistory } from 'react-router';
And now I have this problem:
app.js:2 Uncaught ReferenceError: require is not defined
I searched for require.js, tried some stuff but nothing fixed my problem. What am I missing? I need to run this without webpack or similars tools.
Thanks
for react route v4.0,please read react-router package
add two js link on your page:
<script src="https://unpkg.com/react-router/umd/react-router.min.js"></script>
<script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script>
in js code you can use :
const Router = window.ReactRouterDOM.BrowserRouter;
const Route = window.ReactRouterDOM.Route;
const Link = window.ReactRouterDOM.Link;
const Prompt = window.ReactRouterDOM.Prompt;
const Switch = window.ReactRouterDOM.Switch;
const Redirect = window.ReactRouterDOM.Redirect;
also,can use
console.log(window.ReactRouterDOM);
to out put all object like:
ReactRouteDOM Objects
Here's a minimal example of how this can be accomplished:
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<script src='https://unpkg.com/react#16.3.1/umd/react.production.min.js'></script>
<script src='https://unpkg.com/react-dom#16.3.1/umd/react-dom.production.min.js'></script>
<script src='https://unpkg.com/react-router-dom#5.0.0/umd/react-router-dom.min.js'></script>
<script src='https://unpkg.com/babel-standalone#6.26.0/babel.js'></script>
</head>
<body>
<div id='root'></div>
<script type='text/babel'>
const Link = ReactRouterDOM.Link,
Route = ReactRouterDOM.Route;
const App = props => (
<ReactRouterDOM.HashRouter>
<ul>
<li><Link to="/">TO HOME</Link></li>
<li><Link to="/a">TO A</Link></li>
<li><Link to="/b">TO B</Link></li>
</ul>
<Route path="/" exact component={Home} />
<Route path="/a" component={A} />
<Route path="/b" component={B} />
</ReactRouterDOM.HashRouter>
)
const Home = props => <h1>HOME</h1>
const A = props => <h1>A</h1>
const B = props => <h1>B</h1>
ReactDOM.render(<App />, document.querySelector('#root'));
</script>
</body>
</html>
Use this on top of your javascript:
var Router = ReactRouter.Router;
var Route = ReactRouter.Route;
var IndexRoute = ReactRouter.IndexRoute;
var Link = ReactRouter.Link;
var browserHistory = ReactRouter.browserHistory;
and remove the import statements.
I'm currently using this react-router package: https://unpkg.com/react-router#3.0.0/umd/ReactRouter.js
EDIT:
Here's an example at CodePen: http://codepen.io/lsmoura/pen/pNPOzp -- it uses no import statements.