3

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.

HPJM
  • 517
  • 8
  • 17
  • Express is for backend, React is for frontend. In react, you could use ajax post to express and then when message returns, checking whether the correct username or password and then user can get message. But make sure you are ajax on the same domain such as if yours is example.com the post address may be example.com/signin. In express yiu can use router.get and router.post etc. Sorry for short answer, if you need longer with more eg. Let know – Michael Seltene Mar 28 '18 at 08:58
  • React post: https://stackoverflow.com/q/38510640/5724536 – Michael Seltene Mar 28 '18 at 09:07
  • For express... app.post('/login',function(req,res){res.send('responded')} – Michael Seltene Mar 28 '18 at 09:09
  • And in express console.log(req) and you should get the post argument in json result. – Michael Seltene Mar 28 '18 at 09:11
  • @ሚካኤልሰልጠነ I'm already using AJAX requests with Axios in my action generators to access API endpoints, in order to pass data from Express to my Redux store. Of course, the same could be done for flash messages, but I'm not sure what the best implementation would be. – HPJM Mar 28 '18 at 09:12

2 Answers2

6

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.

ColdFire
  • 6,764
  • 6
  • 35
  • 51
HPJM
  • 517
  • 8
  • 17
0

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.

Community
  • 1
  • 1
Cisco
  • 20,972
  • 5
  • 38
  • 60
  • 2
    `window.flash` won't be available unless you set it. It's available in the response - which is why Jade can be used as the templating language. But if you want to use it in React you have to pass it to the window – Karl Taylor Mar 28 '18 at 15:34
  • 2
    So how can I pass `res.locals` to the window with React? – HPJM Mar 29 '18 at 02:21