Fetching API from react sending me wrong URL - node.js

Learning React.js and Node.js and making a simple crud app with Express API on the back-end and React.js on the front end.
App.js of my React.js looks like this.
`import React, { Component } from 'react';
import './App.css';
import Rentals from './components/Rentals';
import Idpage from './components/Idpage';
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom';
class App extends Component {
render() {
return (
<div className="mainappdiv">
<Router>
<main>
<Route exact path="/" component={Home} />
<Route exact path="/rentals" component={Rentals} />
<Route path="/rentals/:propertyid" component={Idpage} />
</main>
</div>
</Router>
</div>
);
}}
export default App;
I am making an app that when if you go to /rentals, it will fetch the data and print stuff. This is currently working and all the data from my database is rendering.
Now I am trying to go to /rentals/1 or /rentals/2 then trying to print only listings of that id.
import React, { Component } from 'react';
class Idpage extends Component {
componentDidMount() {
fetch('api/listofrentals/2')
.then((response)=>{
console.log(response)
return response.json()
})
.then((singlerent)=>{
console.log(singlerent)
})
}
render() {
return (
<div>
<p>this is the id page solo</p>
<p>{this.props.match.params.propertyid}</p>
</div>
);
}}
export default Idpage;
When I do this, I get an error saying GET http://localhost:3000/rentals/api/listofrentals/2 404 (Not Found)
I am trying to fetch from the URL http://localhost:3000/api/listofrentals/2 and do not understand why the "rentals" part is in the url.
My React server is running on localhost:3000 and node.js is running on localhost:30001. And my React's package.json has this "proxy": "http://localhost:3001/"

Fetch by default will access a relative path to where you are using it. You can specify you want to bypass the relative path by starting your url with /.
fetch('/api/listofrentals/2')

In case if you want to change the base url for testing. You can turn off web security in Google and use.
In ubuntu command line it is
google-chrome --disable-web-security --user-data-dir

Related

What's wrong with my routing in my react application?

I have a React application that I just deployed to my server and now the routing isn't working as expected. I need some help figuring it out.
When running locally, this works:
<button className="welcome-buttons"
onClick={() => window.location.href = 'http://localhost:3000/services'}>
Read More <i className="fas fa-arrow-alt-circle-right"></i>
</button>
I would click on the button and it would route to http://localhost:3000/services. Then when I was ready to deploy, I changed this to http://www.assertivesolutions.ca/services, created a build and uploaded it to my server. I would go to my site (http://www.assertivesolutions.ca) and it would load fine, but when I clicked on the button, I get taken to a page that says Cannot GET /services.
I'm not sure why this is. Maybe I can't just replace localhost:3000 with www.assertivesolutions.ca in the code. But what is the right way to do it?
This is what I have in app.js
import React, { Component } from 'react';
import './App.scss';
import './Home.scss';
import Header from './Header/Header';
import Banner from './Banner/Banner';
import Welcome from './Welcome/Welcome';
import MainFocus from './MainFocus/MainFocus';
import WhatWeDo from './WhatWeDo/WhatWeDo';
import OurBlog from './OurBlog/OurBlog';
import OurClients from './OurClients/OurClients';
import ContactUs from './ContactUs/ContactUs';
import Footer from './Footer/Footer';
import smoothscroll from 'smoothscroll-polyfill';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Blog from './Blog/blog';
import OurServices from './OurServices/OurServices';
import SideMenu from './SideMenu/SideMenu';
class App extends Component {
render() {
smoothscroll.polyfill();
return (
<Router>
<Switch>
<Route path="/" exact>
<div className="app-master-container">
<SideMenu pageWrapId={'page-wrap'} outerContainerId={'outer-container'} />
<div className="header"><Header /></div>
<Banner />
<Welcome />
<MainFocus />
<WhatWeDo />
<OurBlog />
<OurClients />
<ContactUs />
<Footer />
</div>
</Route>
<Route path="/blog">
<Blog/>
</Route>
<Route path="/services">
<OurServices/>
</Route>
</Switch>
</Router>
);
}
}
export default App;
On the server, I'm running node and bouncy to handle the routing to each website I host, like this:
const bouncy = require('bouncy');
const express = require('express');
const path = require('path');
const { create, engine } = require('express-handlebars');
bouncy(function(req, bounce) {
const host = req.headers.host;
console.log(`host=${host}`);
if (host === 'shahspace.com' || host === 'www.shahspace.com') {
if (req.url.includes('/music%20mixes/')) bounce(8002);
else bounce(8000);
}
if (host === 'assertivesolutions.ca' || host === 'www.assertivesolutions.ca') bounce(8001);
if (host === 'fmshahdesign.com' || host === 'www.fmshahdesign.ca') bounce(8003);
}).listen(80);
const fmsApp = express();
fmsApp
.use(express.static(path.join(__dirname, 'fmshahdesign.com')))
.listen(8003);
const assertSolApp = express();
assertSolApp
.use(express.static(path.join(__dirname, 'assertivesolutions.ca')))
.listen(8001);
const musicMixApp = express();
musicMixApp.engine('.hbs', engine({
extname: 'hbs',
defaultLayout: false
}));
musicMixApp.set('view engine', 'hbs');
musicMixApp.set('views', path.join(__dirname, 'shahspace.com/music mixes/views'));
/****** more code for handling music mix app ********/
In other words, all requests come in on port 80 where the node router is listen, and then it checks the host to see which website is being requested. That's where bouncy comes in. It bounces the request to the appropriate port corresponding to the requested website. assertivesolutions.ca is on port 8001 so it bounces it there. Each site has an app created with express which handles the request on the appropriate port.
This works as long as I go to www.assertivesolutions.ca but as soon as I go to www.assertivesolutions.ca/services, it get the Cannot GET /services message. I would create a services folder in the assertivesolutions.ca folder (where the assertSolApp directs requests to) but the contents were created by the build (which I would think should be able to handle requests for /services) so I don't think I should mess with that.
Can anyone see the problem? Thanks.
If you're not sure about your url . Instead of Redirect to Another Webpage with vanilla javascript you can use react router (which you're already using and it seems version 5 ) .
Just add it to your component like this :
in functional components :
import { useHistory } from "react-router-dom";
..............
let history = useHistory();
<button className="welcome-buttons"
onClick={() => history.push("/services")}>
Read More <i className="fas fa-arrow-alt-circle-right"></i>
</button>
in class components :
You can get access to the history object’s properties via the withRouter which is a higher-order component. you can do something like this :
import { withRouter } from "react-router-dom";
class Example extends React.Component {
render() {
return (
<div>
.........
<button className="welcome-buttons"
onClick={() => this.props.history.push("/services")}>
Read More <i className="fas fa-arrow-alt-
circle-right"></i>
</button>
</div>
);
}
}
export default withRouter(Example);
this is a simple codesandbox showing how o implement withRouter
You need to write the .htaccess file in the server root directory.
Check this link

Unable to send api response data from express to react after refreshing the page

I'm learning react and node js with express framework and I'm working on a project where I need to retrieve API data from express to react.
I retrieved data from backend express js where I made a simple json value. My backend server.js code is given below.
server.js
const express = require('express')
const app = express()
const PORT = 3001;
app .get('/api/contents',(req,res)=>{
const contents=[
{
"id":0,
"heading":"Joshua Tree Overnight Adventure",
"content":"A sight in the blue sea..."
},
{
"id":1,
"heading":"Catch waves with an adventure guide",
"content":"Lorem.."
},
{
"id":2,
"heading":"Catch waves with an adventure guide",
"content":"Lorem epsum ..."
}
];
res.json(contents)
})
app.listen(PORT,()=>{
console.log("express server is running...")
})
In react app, I used axios to retrieve those values from backend and tried to pass the api values of content with id= 0 as props in "TheLatestArticles" component. I have updated proxy in package.json in react to connect backend. The below code is the mainhomepage component where it is enclosed with TheLatestArticles component with props value
MainHomePage.js
import axios from 'axios';
import {useState,useEffect} from 'react'
function MainHomePage(){
const [content,setContent]=useState([]);
useEffect(()=>{
const fetchPosts = async ()=>{
const res =await axios.get("/api/contents")
setContent(res.data)
console.log(res)
}
fetchPosts()
},[])
return (
<>
<TheLatestArticle content={content} />
</>
);
}
export default MainHomePage;
TheLatestArticle.js
import cardImage from "./../../Images/card.jpg"
import './TheLatestArticleCard.css';
const TheLatestArticleCard=(props)=>{
console.log(props)
return(
<>
<div className="card">
<div className="image">
<img src={cardImage} alt="cardimg"/>
</div>
<div className="content">
<p className="heading">{props.content.heading}</p>
<p className="body-content">{props.content.content}</p>
<div className="details">
<p className="details-info">Travel <span className="details-info-2">/ August 21 2017</span></p>
</div>
</div>
</div>
</>
)
}
export default TheLatestArticleCard;
When I run the application, It displayed all the api values in the screen given below.
I console.log the api values inside useEffect and it displayed all the api values perfectly.
But when I refresh the page, the api value became undefined and gave me this error
Can you please solve me this issue with the reason behind this error? Thanks a lot!
Try it like this
{(content && content.length > 0) && <TheLatestArticle content={content} />}
Since your API call is async there won't be any data in content initially. After a while, your API is called and data is fetched. Then you will have data. To prevent TheLatestArticle to blow up we add some conditions when to show that component. The error in the screenshot is when you try to use a property heading from content where content is empty.
Now with the condition, TheLatestArticle will not render until there is some data.
Update
You are using <TheLatestArticle content={content} /> and content is assumed to be an object. But as per your code, it's an array. If you are not already using content.map((c)=> <TheLatestArticle content={c} />) you should do that.

React TypeError: location is undefined

I am currently working on creating a boilerplate react application. I have been following these tutorials, but I haven't been able to get past the first tutorial.
I created my app with create-react-app
When I try to run my app, it compiles, but I get an error that says:
TypeError: location is undefined
This error points to the ReactDOM.render( line in this code
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
registerServiceWorker();
If it is relevant, here is my app.js file as well
import React from 'react';
import { Route } from 'react-router-dom';
import { HomePage, LoginPage } from "./components/pages";
import { Grid } from 'react-flexbox-grid';
import 'react-flexbox-grid/dist/react-flexbox-grid.css';
const App = () => (
<Grid fluid>
<Route path='/' exact component={HomePage} />
<Route path='/login' exact component={LoginPage} />
</Grid>
)
export default App;
I've also tried creating a new react app. For the first time, I ejected the app so that I could add css modules, then when I tried to build it again, I used custom react scripts. The problem began about when I ejected the app, but I'm sure if that was the problem because I did rebuild it and copy the src folder over to the new app.
Finally, here is a screenshot of the errors that I am getting.
I've been stuck on this problem for the past 2.5 days, so any help would be greatly appreciated. Thank you so much in advance.
UPDATE: Hey guys. I'm an idiot. The <Link> component uses a to attribute unlike the a tag's href. That was my problem. Really. Well there goes 3 days down the drain and all of your time. Thank you for your help anyway, I appreciate all that you have done.
EDIT - Explanation of the Resolution (as described in #Vishah's answer)
I'm adding an edit here in hopes of helping anyone who comes across this.
The source of the issue was the Links components included "href" attributes instead of "to" attributes.
- <Link href='/'>Home</Link>
+ <Link to='/'>Home</Link>
Additionally, it's worth noting the "href" didn't throw an attribute error because lowercase attributes are still valid dom in React ^16.2.
Here's the commit on his repo: https://github.com/vishalmshah/MERNStackBoilerplate/commit/73fb3fe2e39ffa870fb91bd8b3592887886e3dbb
This was not the source of the issue
I think I see the issue. BrowserRouter uses the location object to keep track of where you are, your history, and possibly other locations the app will navigate to.
BrowserRouter Routes require being given location object which they can use to compare their path value to.
You've got your Route's wrapped by your App object without passing the location object down.
Try passing location through your app:
const App = ({ location }) => (
Subsequently you may have to access the location in the Routes:
<Route location={location} ...
This example is where I got the information from:
https://github.com/Remchi/bookworm-react/blob/master/src/App.js
UPDATE: Hey guys. I'm an idiot. The component uses a to attribute unlike the a tag's href. That was my problem. Really. Well there goes 3 days down the drain and all of your time. Thank you for your help anyway, I appreciate all that you have done.
One thing I notice immediately is how you are importing the components...
import { HomePage, LoginPage } from "./components/pages";
You can not do this... Instead:
import HomePage from './components/pages/HomePage';
import LoginPage from './components/pages/LoginPage';
Also, you should not install react-router but just react-router-dom...
Here is the App.js
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import HomePage from './HomePage';
import LoginPage from './LoginPage';
const App = () => (
<Switch>
<Route path="/" component={HomePage} exact={true} />
<Route path="/login" component={LoginPage} exact={true} />
</Switch>
);
export default App;
And here is the Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'),
);
registerServiceWorker();
Note: I did not create the pages directory and am also using Switch... (docs: https://reacttraining.com/react-router/web/api/Switch)

Authenticated routes with React and PassportJS

I am using the following stack :
React
React router v4
PassportJS
NodeJS backend with Express and
Express session
I have successfully setup PassportJS based login and registration authentication. All pages in my app are protected routes - they can only be viewed by a logged in user.
So, my question is, for each route, how do I check if the user is currently logged in or not. I understand that express session provides server-side session management, but I'm wondering if there's a way to avoid making an API request to the backend on each page load to verify if the session of the current user exists.
My App.js file:
import React, { Component } from 'react';
import './App.css';
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom';
import AsyncAuthPage from 'components/AsyncAuthPage/index.js'
const NoMatch = () => (
<p>Path not found</p>
);
const HomePage = () => (
<div>WELCOME!</div>
);
class App extends Component {
render() {
return (
<div className="App ">
<BrowserRouter>
<Switch>
<Route path="/login" component = {AsyncAuthPage} />
<Route path="/home" component = {HomePage} />
<Route path="*" component={NoMatch} />
</Switch>
</BrowserRouter>
</div>
);
}
}
export default App;
The AsyncAuthPage component implements PassportJS based authentication. In the above sample, I would like to protect Homepage route with authentication. How can this be done? After a user has successfully logged in, the following needs to be taken care of :
The parent App.js needs to know that login was successful
All pages should try to avoid making an API call to the backend (on
componentDidMount or page load) as much as possible, to verify if current user is logged in.
Should work on page reload too

React w/SignalR - TypeError: WebSocketClient() not a constructor

new to React development.
I am building an API client for the BitTrex Exchange API, using their node.js wrapper: node.bittrex.api
With the objective of simply testing the websocket subscription for orderbook updates within the ReactJS framework, here are the steps I have taken:
-Used create-react-app to create the app.
-used npm to install the node.bittrex.api
-added the bittrex client object to the top of the default App.js component and configured options with proper API keys
-added a button (with handler, binded to the button according to React docs) to the default App.js main component,
-inside the handler function, initiated the websocket subscription according to the example code in the node.bittrex.api docs.
The app comes up, but when I press the button, I get an error saying that TypeError Websocketclient() is not a constructor, in the line inside the SignalR.js that creates the websocket connection:
Now I suspect that there is just something specific with the React framework that is screwing this up. Can anyone please help me understand the intricacies? Thanks. Here is my App.js:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
var bittrex = require('../node_modules/node.bittrex.api/node.bittrex.api.js');
bittrex.options({
'apikey' : process.env.REACT_APP_BTREX_API_KEY,
'apisecret' : process.env.REACT_APP_BTREX_SECRET_KEY,
'verbose' : true,
'cleartext' : false,
'baseUrl' : 'https://bittrex.com/api/v1.1'
});
class App extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
bittrex.websockets.subscribe(['BTC-ETH','BTC-ANS','BTC-GNT'], function(data) {
if (data.M === 'updateExchangeState') {
data.A.forEach(function(data_for) {
console.log('Market Update for '+ data_for.MarketName, data_for);
});
}
});
}
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<br/>
<button onClick={this.handleClick}>Start WS Sub</button>
</div>
);
}
}
export default App;

Resources