Using React to render flash messages from Express - reactjs

I've searched around a lot but have been unable to find a simple way to get flash messages from Express and render them in React.
I need to access the data on my Express server, but what is the best way of storing this and passing it down to React? I was thinking of passing an object down when the React index.html file is rendered, but I'm not sure how I can access this data, or send the correct data when certain events happen, for example a user enters the wrong password.

I solved the issue.
I simply have a variable in my session called flash which is set to false by default.
In the correct part of the passport flow I redefine this to a string, depending on the error. I have a React action and reducer to get this data and if it's truthy, render it to the screen. When the component unmounts or the site is refreshed I reset it to false.
EDIT: I have found a better solution
1. In the passport middleware set an optional message if something goes wrong.
return done(null, false, { message: 'Email not found' });
2. In the login route send this information as a response.
router.post('/login', (req, res, next) => {
passport.authenticate('local-login', (e, user, info) => {
if(e) return next(e);
if(info) return res.send(info);
req.logIn(user, e => {
if(e) return next(e);
return res.send(user);
});
})(req, res, next);
});
3. Handle the submission and response in a Redux action generator. If the user authenticates, then the message property will be undefined.
const res = await axios.post('/auth/login', { email, password });
dispatch({
type: 'FLASH',
payload: res.data.message
});
4. In the reducer, the state will be either a string or false:
return action.payload || false;
5. Then it's a question of rendering the state to the screen. Another action can be sent when the component unmounts to reset the state.
Hope this helps someone else out there.

expressjs/flash will place an array of flash objects onto res.locals. Per the docs: https://github.com/expressjs/flash#reslocalsflash
res.locals.flash
An array of flash messages of the form:
{
"type": "info",
"message": "message"
}
From my understanding, anything placed on res.locals is available in the global scope. In other words, you should be able to do window.flash which should return an Array of flash objects.
So you would simply loop over the array as you would normally in JavaScript. That is just my guess.
const makeFlashElement = ({type, message}) => {
return (
<div>
<h1>message</h1>
<h2>type</h2>
</div>
)
}
for (message in flash) {
makeFlashElement(message)
// ...
}
Typically you'd return a JSON response which React can easily digest.
See Karl Taylor's comment.

Related

Reactjs: Show logged in or log in accordingly to session

I am trying to get better in react and I would like to do it everything correctly which is why I am asking for your opinions and help.
I am building a project in NextJS and I have a layout component which contains components which are rendered multiple times such as header, footer etc.
I this header, I have a "Sign in" and "Sign out" button. I'd like it to only show one of them accordingly to your session status.
I use a sessionid which contains some more info in the database and this sessionid is stored in a httponly cookie.
It is stored in the database with data:
id
sessionid
userid
expires
Would you add or remove anything to this?
So my question is:
How would you check for a session and then render x accordingly? Would you just send an api call each request that checks the session or? Should I maybe use useContext and create a provider which can then send the session with the provider?
I'm quite lost on how to do it the best way so the flow is smooth as f*ck.
It depends how strict you want to be with it.
One option would be to simply check the existence of the cookie and adjust according to that. You can use js-cookie for that.
The better option, in my opinion, is to verify the cookie with your backend. You should set up an endpoint that simply verifies / parses the cookie and returns something like the user_id, or ismply a boolean indicating whether the user is logged in.
Given that you are using Next, you can add this call to your App's getInitialProps() like this:
App.getInitialProps = async () => {
let loggedIn;
try {
({ data: {loggedIn} } = await axios.get('/api/v1/auth/checkCookie'));
} catch (err) {
console.log('Error checkingCookie', err.message );
}
return {
loggedIn,
}
}
Your loggedIn variable will then be available in the props of your App, like:
function App({currentUser}) {
if (currentUser) {
return <div>Logged In</div>
} else {
return <div>Logged Out</div>
}
}

CHROME EXTENSIONS: Message passing - chrome.runtime.sendMessage or onMessage not working

I am working on google extensions. I am trying to process message passing between my popup.tsx and background.ts
Before sending message from my background.ts, I print the data. Data exist. However, in my popup.tsx chrome.runtime.onMessage not triggered. I dont understand which function not working and what is the problem. I examine lots of example but result still the same. What is the problem? I am adding my message passing codes..
Here is my background.ts runtime.sendMessage func. this function is inside another function that is called 'collectData'. When I open new tab or update the tab, this function triggered and works. Everytime this data works stable. I can see the data in every page.
chrome.runtime.sendMessage({
msg: 'url_data',
data: data,
})
Then, I am trying to receive the data in my popup.tsx with runtime.onMessage. When I reset the extension, it works sometimes just once, then that onMessage func not working at all :
const [requestData, setRequestData] = useState<string>()
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log(' popup runtime on message req', request)
if (request.msg === 'url_data') {
checkWebsite(request.data).then((res) => {
console.log('popup data alındı')
console.log('popu res', res)
setRequestData(res)
// chrome.runtime.sendMessage({
// msg: 'res_length',
// data: res.matches.length,
// })
// console.log('popup data res length gönderildi')
// res.matches.length === 0 ? setIsSecure(true) : setIsSecure(false)
setHost(request.data.hostname)
})
sendResponse({ message: 'res length sended' })
console.log('res length response send')
}
})
Everytime, I change request data state. If it changes, I want to update popup with useEffect.
useEffect(() => {
console.log('useeffect', requestData)
}, [requestData])
As a result, for the first the main problem is message passing. Why it is not working?

Confirm remote sync - Firebase Realtime Database w/ ReactJS+Redux+Saga

I have a ReactJS/Redux/Saga app which currently sends and reads data from a Firebase Realtime Database. As data is sent and received, there's a global redux state value loading, which toggles between true and false between sending data and confirming that data is now in Firebase. loading defaults to false for this case.
When a user updates their data, the flow is currently:
Redux reducer SEND_TO_FIREBASE
return { ...state, loading: true };
This reducer triggers a Saga function sendToFirebaseSaga()
function* syncToFirebaseSaga({ payload: userData }) {
try {
var uid = firebase.auth().currentUser.uid;
const database = (path, payload) => {
firebase
.database()
.ref(path)
.set(payload);
};
yield call(database, "users/" + uid + "/userData", userData);
yield console.log("successfully written to database");
} catch (error) {
alert(error);
}
}
So, at this point loading:true (confirmed that this works)
Then, as a part of componentDidMount of one of my root components, I have a listener for changes to the Firebase Database:
var props = this.props
function updateStateData(payload, props) {
props.syncFirebaseToState(payload);
}
function syncWithFirebase(uid, props) {
var syncStateWithFirebaseListener = firebase.database().ref("users/" + uid + "/userData");
syncStateWithFirebaseListener.on("value", function(snapshot) {
var localState = snapshot.val();
updateStateData(localState, props);
});
}
and this.props.syncFirebaseToState(payload) is a Redux action with this reducer:
return { ...state, data: action.payload, loading: false };
which then confirms that the data has been written to the Firebase Realtime Database, and then takes down the loading page, letting the user know that their update is now safe.
For most cases, this flow works fine. However, I run into problems when the user has a bad internet connection or if I refresh the page too fast. For example:
User loads app.
Disconnects from internet.
Submits data.
Full loop works immediately and loading:false (Firebase Realtime Database wrote it in 'offline mode' and is waiting to be reconnected to the internet)
User reconnects online.
Once online, user immediately refreshes the page (reloading the React app)
Firebase Realtime Database didn't have time to sync the queued updates to the remote database, and now after page refresh, the edits don't make it.
Sometimes, the user doesn't have to lose their internet connection. If they submit an edit (the page instantly returns a 'successful read') and then refresh before the remote server writes it down, the data is loss after the refresh is complete.
Anyway, as you can see, this is a really bad user experience. I really need a way to confirm that the data has actually been written to Firebase before removing the loading screen. I feel like I must be doing something wrong here and somehow getting a successful callback when it isn't.
This is my first time using React/Redux/Saga/Firebase, so I appreciate the patience and the help!
You could just disable offline mode.
I am assuming you don't want to do that so the next thing is to add a condition to check if your update is coming from the cache or the database.
Firebase Realtime Database provides a special location at /.info/connected which is updated every time the Firebase Realtime Database client's connection state changes. Here is an example:
var connectedRef = firebase.database().ref(".info/connected");
connectedRef.on("value", function(snap) {
if (snap.val() === true) {
alert("connected");
} else {
alert("not connected");
}
});
You can then run this check alongside your update to turn to load off and then propagate the change depending on whether it's coming from cache or the actual database.

navigator.geolocation.getCurrentPosition() is not getting a response from googleapi

I am using react to get geolocation on localhost:3000. I have seen another person get the geolocation coordinates on their localhost, but I am unable to do so even with allow location access enabled on Chrome.
I have tried using both the hooks and class syntax in react. I have enabled allow access. I eventually used an ip address api to get a general location, but since the geolocation is supposed to work(at least that is what I have been told) I would at least like to see it work so I can implement it with https in the future. The error log does not even get fired, whereas the first three logs are getting fired when the component is mounted. Here is the code I have tried, I have made it as simple as possible:
const App = props => {
useEffect(() => {
console.log('hello')
console.log(navigator)
console.log(navigator.geolocation)
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
console.log(position)
}, (error) => {
console.log(error)
})
} else {
console.log('error')
}
}, [])
return (
<div>
<h3>Please Login.</h3>
</div>
)
}
export default App
I expect to receive a response from googleapi.
Edit:
I added the error callback and it printed:
message: "Network location provider at 'https://www.googleapis.com/' : No response received."
add the optional error callback to handle the error (if user declines location permission)
navigator.geolocation.getCurrentPosition(success[, error[, [options]])
you are checking only if it is in navigator or not !!!
if user declines location permission then error callback will handle it...
possible options are (reference taken from mdn)
{
enableHighAccuracy: true,
maximumAge : 30000,
timeout : 27000
}

React JS & Axios chaining promies

I am developing a react js application and we are using a promise based library axios for calling APIs.
Now, in the initial part of application, user gets a login page, when the login is successful, we contact different systems to retrieve some extra information about user.
axios
.get('url to authentication endpoint') // 1st call
.then(response => {
// if login is successful
// 1. retrieve the user preferences like, on the customised screens what fields user wanted to see
axios.get('user preference endpoint') // 2nd call
// 2. send a request to one more external systems, which calculates what user can see and not based on LDAP role
axios.get('role calculation endpoint') // 3rd call
})
.catch(error => {
})
Now I can see that I can use
axios.all()
for second and third call, but with promised based client, how to chain first and second call? To retrieve user preferences, I have to wait for user to be authenticated.
How to chain this calls in a promise based way, rather than callback style?
as mentioned in the thread for this Github issue, axios() and axios.all() return Promise objects which can be chained however you see fit:
axios.get('/auth')
.then(function(response) {
return axios.all([ axios.get('/preferences'), axios.get('/roles') ]);
})
.then(function(responses) {
const [
preferencesResponse,
rolesResponse
] = responses;
// do more things
})
.catch(function(error) {
console.log(error);
});
Dan O's answer is very good and it works perfectly but it's much readable using async/await although it's also working with promises under the hoood
async yourReactClassFunction(){
try{
let getAuth = await axios.get('/auth');
//if login not successful return;
let result = await Promise.all([axios.get('/preferences'), axios.get('/roles')]);
//Do whatever with the results.
}catch(e){
//TODO error handling
}
}
Although it's the same thing, 'feels' more readable in my very subjective opinion

Resources