React Router V5 | setup 404 page | status from API - reactjs

I am building a React JS app with react-router v5.
I have already set up a 404 page and it works well.
As you can see, in the console I’m getting response code I just need to understand how to set a 404 header in the React component from this api response.
I looked up this question and everyone says you should set it from server response, but I did not figure it out, because I'm here now for your help.
Thank you
import React from "react";
const baseURL = "https://dog.ceo/api/breeds/image/";
const phpRoute = "giveme404"; //if you put here "random" will work
class NotFoundPage extends React.Component {
componentDidMount() {
fetch(baseURL + phpRoute)
.then(response => response.json())
.then(function(response) {
console.log(response);
});
}
render() {
return <div>404 Error, Page not found</div>;
}
}
export default NotFoundPage;
codesandbox link
Response From Server
Get response from server to React

Here's an example error handling strategy you can adopt on the frontend.
Some highlights:
I added some sample React routing with 404 page to which to redirect
when certain conditions occur.
I used the axios library, because I'm not sure if the built-in fetch
method in JS offers the same control as axios in terms of global
error handling. Logic for api access logic is in api.js file, there
you can see I added an error interceptor (more about interceptors here) which kicks off whenever
there's an unhandled http error and redirects to the not found page
only in case of 404 status code.
The trickies part is the history object. As you may know, React
router keeps internally its own history object which handles route change subscriptions and you can't create
your own one and expect React to detect changes from it. So you must
access this object instead, it's harder to do it outside of a React
component, though. All routed components like MyFeatureComp receive
automatically the history object as prop. In its componentDidMount I
store that value in a global variable so I have access to it in the
api logic, but you'll need to come up with better approach I think, it's just for demo purposes.
Outside of this sample, error boundaries are nifty mechanism to handle errors in your render functions (not event handlers) (for either class or functional components). In my experience, I've used them mostly with the render-as-you-fetch strategy to incorporate them with the error boundaries. With that approach the request is effectively made in the render function as opposed to any callbacks like componentDidMount. But this is probably not the standard yet and official support will come probably in next major version, React 17.
I hope that helps, let me know if you have questions. ;)

Related

Handling errors in React (Error Boundary, React-Query, Axios Interceptor)

I have a Create React App (that uses react-router v6) that is setup the following way to communicate with the API.
At the top level - I wrapped my app in an ErrorBoundary (Sentry.ErrorBoundary).
When fetching the API, the front-end calls a useQuery method from react-query (which uses an axios instance to fetch the requested API URL).
But how do I handle an error 404 or 500 from axios?
Currently the ErrorBoundary renders an ErrorPage that is blocking the UI. I'm trying to find a better way that don't block the UI.
The way I see it, I can handle errors in the following way:
using axios interceptor directly - but currently it's in a separate file and don't use useNavigate() of React Router - so either I use window to redirect to /404 or /500 or I wrap it inside a React.Context (itself wrapped in my React Router context) so that it can use useNavigate() inside of it from react-router to redirect to /404 or /500.
using onError handler from react-query (directly inside my QueryClient config) that will be passed an AxiosError and redirect to /404 or /500 based on axios error response status
Using the error object that comes from Sentry.ErrorBoundary and render a different UI based on the error response status from axios
Solution 1 and 2 will leverage useNavigate() by react-router to redirect (or window.pathname) but I'm not satisfied with these... The solution 3 is more interesting for me (as I can have a 404 UI without changing pathname!) but the solution 3 does not handle the error (it'll be uncaught)...
Any recommendation or better idea?
I haven't found that much regarding handling errors in an SPA - thank you for your time :)

React and React Native pattern for handling server responses

In the past I did lots of native mobile development on both Android (Java) and iOS (ObjC and Swift). For my server-connected apps, one issue that I had to handle properly was the callback that was called after the app made an HTTP request. For example, suppose I have a screen (an Activity in Android or a ViewController in iOS), and inside that I make an HTTP request to a REST server, expecting some data in response. Most textbooks (unfortunately) provide examples of the HTTP response calling a callback method within the Activity or ViewController itself. Yes it seems reasonable at first glance but there is a big problem in apps with multiple Activities or ViewControllers - what happens if the user navigates away from the screen after the request but before the response comes back? In this case, the app destroys the memory of the first Activity or ViewController, so when the response comes back, it tries to call a method on freed memory, resulting in a crash.
What we had to instead was to use a persistent singleton object (like a class that extends Application in Android or use the appdelegate in iOS) as the class that implemented the callback functions. Any screen that wanted to get results had to register for those results (using listeners in Android or using notifications in iOS). If the user navigated away from the screen, the screen's appropriate lifecycle methods would unregister the listener/notification handler in the screen so that there would never be a case where a callback method is called on freed memory.
Now I am starting to use both React (in browsers) and React Native (in mobile apps). I am using the Axios module for handling HTTP requests. Once again, all the examples I see show callbacks in the React component itself rather than any kind of pattern where there is some sort of persistent singleton or global object that handles the responses and dispatches them to any screens that are still active on the display.
So I have several questions as follows:
For React (in a browser), is this a concern? Can/should I just provide a callback on the component itself, and the browser will not have a problem if I navigate away from the screen mid-request? I suspect browser code is pretty robust these days so I doubt it would crash the browser but would it cause any issues with the webapp?
What about React Native? Since this is basically built on top of mobile native code, will I run into this memory crashing problem if I put the callback in the component itself?
If this is a problem, is there a good pattern to use for a central global persistent object to handle callbacks and dispatch the results to any registered components?
Note that I won't be using redux in my code - instead I plan to use a simpler framework (hookstate, hookstate.js.org) that lets me keep track of global state and use it inside components when updated. This seems sortof like a callback system for global state but it isn't quite clear to me the best pattern for incorporating HTTP requests through modules like Axios into it.
Suggestions?
The answer will probably depend heavily on how you are doing state management within your application. However, assuming you are using a version of React Native that supports hooks, something like this might be a useful pattern to get started:
import React, {useState, useEffect} from 'react'
import axios, {CancelToken} from 'axios'
const MyComponent = () => {
const [blah, setBlah] = useState(null)
useEffect(() => {
//Axios comes with support for cancelling. See here
//https://github.com/axios/axios#cancellation
const source = CancelToken.source();
let source = null
axios.get('/some/url', {cancelToken: source.token})
.then(({data}) => {
//If the request is successful, we know the component wasn't unmounted.
//Go ahead and call the state-modifying function.
setBlah(data)
})
.catch((thown) => {
//If something goes wrong, check to see if it is because of a cancel.
//If it is, we probalby don't need to do anything.
if (axios.isCancel(thrown)) {
console.log("Cancelled")
}
else {
//Otherwise, we can handle the error gracefully
}
})
//If you return a function from setEffect, it will be
//executed when the component is about to unmount (componentWillUnmount)
//See https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1
return () => source.cancel()
}, []) //This will only run once (the first time the component renders)
return <pre>{blah}</pre>
}
Essentially, we are using useEffect to trigger the request via Axios. We then utilize Axios' built-in cancel functionality (https://github.com/axios/axios#cancellation). We call the cancel function when the component is unmounted. As a result, the then clause of the axios request won't execute. In this particular case, it doesn't really matter; we are using state internal to the component, so there would be no effect of setBlah running after unmount. However, if say you were using Redux for global state, or some other reducer pattern, it is possible that your then clause would trigger some external action even after unmount.
So, to answer the question of "does it matter"? The answer is, "It depends". If you can keep your state local to the component that issues the request, perhaps not. If, like you allude to, you plan to have some global state and expose ways to modify that state (Redux, or a context that exposes a reducer), then it certainly could. A pattern like this should avoid ever calling the state-modifying function in the event your component is unmounted.
Caveat - I haven't tested this code. Most of it is derived from the links I provided, which hopefully should provide any additional context necessary (or corrections if I got an implementation detail wrong).

How to make React ignore one route?

I'm working on a project that, for reasons too long to get into, at one point needs to redirect the user to the API. The problem is that the API and the React front end are on the same domain. So when the browser requests mydomain.com/api/blahblahblah, it gets picked up by React Router and never reaches the API.
I need React to ignore requests to that one particular route and to let the API handle it.
The app is hosted on Heroku so there's a chance this is a Heroku issue, not a React issue.
If you simply use the good old anchor tag (a tag) you should get the desired effect.
Also, you can trigger a redirect using JS:
<MyComponent onClick={ () => window.location.href = 'this/awesome/url/' } />

What's the preferred way of doing POST/GET using react-router?

I have a simple route in React:
<Route path="/listUsers" exact component={UsersList} />
Different component (navigation) holds the link to the UsersList:
<Link to="/listUsers">All users</Link>
My back-end is very simple, once you make get request to /listUsers it responds with all the users, like:
app.get('/listUsers', function (req, res) {
UserModel.find({}, function(err, users) {
res.send(users);
})
})
I'm facing two problems here:
when do I actually make the request? should I perform react's fetch on componentDidMount in UsersList component? or maybe on componentWillMount? so it will work like this - user clicks a link - I'm mounting component via react-router and at the same time - before/after mount performing fetch, does it make sense? I guess after fetching I should update the components internals somehow (possibly using props?),
my node server is at localhost:3000, so I should be hitting localhost:3000/listUsers, yet my React app is being served by Apache at localhost, so the <Link to="/listUsers"> actually points to a wrong URL, I guess I'll be able to provide the proper URL within React's fetch?
I know these are noobish questions but I'm sorry to say I found it very hard to make these clear to me and I'm not sure if https://facebook.github.io/react/docs/hello-world.html is the official React's documentation, because it's simply awful and it's next to impossible to find anything there.
Thank you so much.

How do I add general error handling into my React app?

I am currently building a React app which does a lot of server communication. If a server error occurs, I want to display the error to the user in a general way, e.g. an overlay with the error message.
Using container components
In my reducers, I return something like this:
{
type: "LIST_POSTS_ERROR",
loading: false,
error: {
msg: "An error occurred"
}
}
Obviously, my container components are redux aware. In the render() function, I could check, if the current state has a property error and if so, I would render the error message. Oddly, in every container component, I would have to check the current state and might have duplicated code in every container component.
A more general approach
What am I looking for is a more general approach. Something that knows about all the states and displays the error message automatically if the current state contains an error. Think of it like an interceptor for errors. Of course, this component would not belong to a route, so I am wondering if this is even possible?
How do you do error handling in your React app? I would love to know your approach!
In my app, I've a action called handleError which will trigger a toast component in my app.
You can dispatch this action at the time of error. Like, you can dispatch it in the .catch() of the Promise.
I am trying something similar for my App. So fire a dispatch on catch or >=400 response to set a string(your api response) in state and connect this value to your component.
Next, after maybe 4-5 seconds fire a dispatch to clear that value, so your message would go away. This you can implement in your login screens or your post API calls.
Hope it helps !!!

Resources