POST request from react child component in express - javascript

I am using the MERN stack (With react-router and redux) for my program.
In my application, I have a <Navbar /> component as well as a <SearchBar> component.
I used create-react-app to handle the react side of things, and as i'm sure you all know, everything is ultimately contained within App.js
Within App.js, Navbar is outside of the react router switch statement like so.
<Provider store={store}>
<Router>
<div>
<NavBarContainer />
<Switch>
<Route exact path="/" component={Homepage} />
<Route exact path="/ProfilePage" component={ProfilePageContainer} />
<Route exact path="/SearchPage" component={SearchPageContainer} />
<Route exact path="/LoginPage" component={LoginContainer} />
</Switch>
</div>
</Router>
</Provider>
My problem is that SearchBar is a child component of Navbar like so.
class Navbar extends Component {
render(){
return (
***navbar stuff
{this.props.loggedIn && <SearchBar />}
***navbar stuff
)
}
}
And when I try to make a POST request from <SearchBar /> like this:
addSearch = (event) => {
if(this.props.loggedIn){
fetch('/api/SearchPage', {
headers : {
"Accept" : "application/json",
"Content-Type" : "application/json"
},
method : 'POST',
body : JSON.stringify({
username : this.props.username,
search : this.search.value
}).then(function(value){
return value.json()})
.then(function(data){
console.log("SearchData", data)
}).bind(this)
})
}
}
Where addSearch() is called within the SearchBar with onClick(this.addSearch).
When I do this, the POST request comes from whatever page is rendered under my Navbar!
My page says:
Cannot POST /api/[Pagename}.js
Whatever page is currently rendered under Navbar with react switch will replace [Pagename]
How can I make <SearchBar /> create a POST request within itself?
Or, if that is not possible, how can I contain that post request within the <Navbar> component?
Something I'm considering, is that it has something to do with the fact hat I'm using a body parser, and the current body of the page happens to be whatever page is loaded. However, I seem to define the body: within the POST request so this doesn't make much sense.
For now, i'm simply going to put all of the code and logic of the <SearchBar> component within the <Navbar> and the search page, but I suspect that there is a much better way to do this (while leaving <SearchBar> within its own component).
Ideally, I'd like to send a POST request just from <SearchBar>.
I know I'm probably missing something common here.
Here is the endpoint in the express file (It is just set up for testing)
```
app.post('/api/SearchPage', function(req, res done){
if(err) done(err);
done(null, res.json({"Test" : "testobj"}))
}'
```

From the given code, it seems like its the url in fetch() that is the issue here. Since you are only stating '/app/SearchPage', then it is assumed to be part of the React app (which it is not, since its should hit your API endpoint).
You should try to insert the url for the endpoint. Is is sometimes running on a different port than the React application (depending on your setup). Endpoint could be something like http://localhost:3050/api/SearchPage, which should be set in the URL parameter of your fetch() method.

I took a break today but the answer seems obvious at the moment.
When I do fetch(), all react does is append the URL (in this case /API/Page) to localhost/[pageimon]
Because all of my routing is handled client side by react router, my URL is whatever page I'm on. (I did not do any routing with express).
Since the navbar is out side of all switching (on purpose), whatever is contained in there will not make a successful post request, as all fetch calls will simply read the URL.
So I have to figure out a way to either bypass this (possibly a fetch parameter, or a react middleware module).

Related

How to pass and intercept data with Link in react-router-dom v5 [duplicate]

This question already has answers here:
How to pass data from a page to another page using react router
(5 answers)
Closed last month.
I am making a simple chat-app. Users submit a form with name and room, and are sent to the room, with the username. The problem is, I cannot figure out how to pass the username through via the Link. This is the relevant code:
<Link to={{ pathname: `/${room}`, state: { the: user } }}>
Enter room
</Link>
I use simple useState hooks to set room and username from input. From what I have read, this way of doing it is deprecated, and I cannot find a proper answer for react-router-dom#5, only 4 and below.
Also, I have no idea how I am supposed to intercept this data. This is my App.js code:
return (
<Router>
<div className='app' >
<Switch>
<Route exact path='/'>
<Menu />
</Route>
<Route exact path='/:room'>
<ChatApp />
</Route>
</Switch>
</div>
</Router>
);
So as you can see, the link sends you to the ChatApp component. To make it as simple as possible, the top of that looks like this:
const ChatApp = (props) => {
but when I console.log(props), all I get is an empty array. Does anyone know a reliable way of passing and intercepting data via links? Perhaps it should be done a different way?
Not necessarily the right answer, but the way things look, in rrd#5, you cannot, and you are forced to send the props as params. Not sure for objects though

ContextProvider doesn't mount when page refreshes

Please see the full code on codesandbox.
I have two Route components for my countries api app-
<>
<Header/>
<Router>
<Switch>
<CountriesDataProvider>
<Route path='/' exact component={HomeRoute} />
<Route path='/detail/:countryName' component={DetailsRoute} />
</CountriesDataProvider>
</Switch>
</Router>
</>
The DetailsRoute for each country shows up with all information perfectly when I click on a country on the HomeRoute. But when a direct http request is made or the DetailsRoute is refreshed, I see this error-
/src/comps/Details/DetailsRoute.jsx
Cannot read property 'borders' of undefined
It occurs on the line-
const promises = country[0].borders.map(fetchNeighborName);
country[0] is extracted from countriesData which seems to be undefined-
const {countriesData} = React.useContext(CountriesDataContext);
This is not an issue with BrowserRouter, because the DetailsRoute component does render but with missing info.
I don't kow what logical error is causing it to not work when a direct url request is sent to the DetailsRoute component? Please let me know the fix!
The problem is that when you reload the details page the response in CountriesDataContext hasn't come back yet, so country is empty. An easy way to solve the problem (and is generally good practice) is to add a check to make sure the data is there:
async function resolveBorders() {
// Add a condition to make sure you have the data you expect.
if (country.length) {
const promises = country[0].borders.map(fetchNeighborName);
setBorderCountries(await Promise.all(promises));
}
}
Be sure to also add country to the effect's dependency array so that the effect runs again when the response comes back:
React.useEffect(() => {
async function resolveBorders() {
...
}
resolveBorders();
}, [borderCountries, country]); // <-- Add `country` here

Issue with routing in React when user directly hits url that requires id from another component

I have this issue that I am facing in react related to routing.
There is this button which appears on the screen which appears only if the user is authenticated and thus it's a private route "/home/coupons".
When user clicks on any of the coupons ,I directed the user to
http://localhost:3000/coupons?id=6
Using this props.history:
this.props.history.push({
pathname: '/coupons',
search: '?id='+id,
})
I did the routing for this in my App.js:
<Route path="/coupons" component={CouponsRedeem}/>
The Component CouponsRedeem needs the id from the Component where users gets directed when he hits /home/coupons.
My concern is that if user directly hits the route /coupons without navigating to /home/coupons,the entire web app break since we don't get any get anything in this.props.location.
How do I make sure that such things don't happen?
Is my routing done correctly?
Any suggestions are most welcomed.
If it lacks information ,I will add more code snippets.
I am using react-router.
The solution to your problem is pretty simply. Either you have a default value that you use when the user didn't navigate from home/coupons to coupons since history.location.search doesn't have anything or you reconfigure your Route to use Router param where in instead of query your specify your Route like
<Route
exact
path="/coupons/:id"
component={Coupon.Show}
/>
and use it like
this.props.history.push({
pathname: `/coupons/${id}`,
})
or else if the coupon isn't received you can redirect the user to the home/coupons route
Looking at your implementation, I would assume that you're using either react-router or reach-router ?
If so, in my experience I tend to use route props to specify that an ID should be expected.
I would usually setup a route for the index and a route for showing an object and a default route for no matches (think of that like a 404) like so:
<Route
exact
path="/coupons"
component={Coupon.Index}
/>
<Route
exact
path="/coupons/:id"
component={Coupon.Show}
/>
<Route component={NoMatch} />
Specifying the "exact" prop ensures that it'll only render that component when the path matches correctly, so if you dont want an index route, you could omit it completely and when you navigate to that it'll fall back to the NoMatch component
The example I provided would change how it looks in the address bar for a more RESTful looking approach so instead of
http://localhost:3000/coupons?id=6 it would be http://localhost:3000/coupons/6
In the show component you can then access the prop value by the name that you specify after the colon ":id" in your Show component, using the props provided by the router like so:
let { id } = this.props.match.params;
I hope this helps

How to call setState with componentDidMount without causing extra calls to render?

I have a problem with componentDidMount: everytime that i use setState in componentDidMount it calls render several times in child components, and I don't know why... look:
componentDidMount() {
const firstName = localStorage.getItem('nameLoggedUser');
const lastName = localStorage.getItem('lastNameLoggedUser');
const fullName = `${firstName} ${lastName}`.toLowerCase();
const loggedUserIs = localStorage.getItem("user-role");
const emailLoggedUser = localStorage.getItem('emailLoggedUser');
if (loggedUserIs === 'full') {
axios.get(`/api/menuDomain`)
.then(res => this.setState({
domain: res.data
}))
.catch(err => console.log(err))
}
}
It gives this:
But, if I use ComponentDidUpdate, it gives:
That is correct, but the AJAX call is not happening...
I want to make the AJAX call and not have it render several times... But I don't know how... Could someone help me? Please???
And I am using react-router too:
return (
<Router>
<Switch>
<Route path="/login" component={Login} />
<Route exact path="/" render={() =>
<Overview
{...myProps}
/>
}
/>
<Route path="/list" render={() =>
<Graphic
{...myProps}
/>
} />
</Switch>
</Router>
);
}
}
First, never wrap your routes within a stateful component. Instead, the routes should be a stateless function that just returns the same JSX route elements. For the example above, you should use a HOC that wraps your protected routes and is only concerned with authentication: https://stackoverflow.com/a/53197429/7376526
Second, you shouldn't be storing the logged in user in plain text within local storage. Instead, it and possibly the password should be stored within a JWT token (or within some sort of hashed plus salted token) or perhaps within a secured cookie and then decoded and compared against server-side. How you're currently setting it to localStorage is incredibly insecure and anyone can simply set a user's first and last name and their "user-role" and gain access to their account.
Third, each container should handle and fetch relevant data and pass it to a relevant component for display. For performance, you should compartmentalize your retrieved data to relevant data for that particular component. Since you have multiple routes, fetching everything at once is wasteful. For example, fetch Overview data inside of a FetchOverview container's componentDidMount, then pass it down to a DisplayOverview child component for display. Read this for more information on containers and components: https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

ReactJS route shows empty page

Using ReactJS frontend, with react-router, I somehow get an empty page when being redirected to a new route.
In a component I use the following to achieve a redirect:
if (this.props.showUnknownErrorPage) {
return <Redirect push to={`/${this.props.locale}/unforeseenerror/`}/>
}
This does lead to the correct URL:
http://127.0.0.1:8000/en/unforeseenerror/
But the page that shows is totally empty, just a blank page.
The route that should get the component to show:
<Route path={`${this.props.match.path}/unforeseenerror/`}
render={(props) => <UnknownErrorPage {...props}
setGreeneryAppState={this.setGreeneryAppState}/>}
/>
I have similar routes that look quite the same, and they work without problem. Can anyone help me debug this?
What I have already tried:
Changed component content, to just an H1 element (no difference)
Changed to different route: a one line route like this:
<Route path={${this.props.match.path}/about} component={AboutPage}/>
Tried a hardcoded route path /en/unforeseenerror/
`

Categories

Resources