1

I'm trying to use Redux in my react project. The objective is to have a component that give me a token. I wan't this token to be stored in my App.js so i use redux. But when i try to save changes to the store, it works but it's not re rendering. Here's my code :

App.js

import React, { Component } from 'react';
import LoginApi from './components/LoginApi.js';
import { createStore } from 'redux'
import './App.css';

function pops(state = { sessionToken: '', isLoggedIn: false, group: '' }, action) {
    const { sessionToken, isLoggedIn, group, type } = action;
    switch (type) {
        case 'LOGIN':
            return { sessionToken, isLoggedIn, group };
        case 'LOGOUT':
            return { sessionToken: '', isLoggedIn: false, group: '' };
        default:
            return { sessionToken, isLoggedIn, group };
    }
}
const store = createStore(pops, { sessionToken: '', isLoggedIn: false, group: '', });

class App extends Component {
    render() {
        return (
            <div className="App container-fluid">
                <div className="row text-center">
                    <div className="col-3"><LoginApi store={store} /></div>
                </div>
            </div>
        );
    }
}

export default App;

LoginApi.js

import React from 'react';
import './LoginApi.css';

class LoginApi extends React.Component {

    handleLogout() {
        this.props.store.dispatch({ type: "LOGOUT"});
    }

    handleLogin() {
        this.props.store.dispatch({ type: "LOGIN", sessionToken, isLoggedIn: true, group });
    }

    render() {
        const { isLoggedIn, sessionToken } = this.props.store.getState();
        console.log(this.props.store.getState());
        return (
            <div className="Login">
                {(isLoggedIn === true && sessionToken !== "") ?
                    <button type="button" className="btn btn-danger" onClick={this.handleLogout}>Logout</button>
                    :
                    <button type="button" className="btn btn-primary" onClick={this.handleLogin}>Login</button>
                }
            </div>
        );
    }
}

export default LoginApi;

handleLogout and handleLogin are calls to my API using axios. I skiped this to be clearer.

1
  • That doesn't sound like a good justification for using Redux. Can you explain what you mean by wanting to store the token in your app? Commented Mar 27, 2019 at 21:14

2 Answers 2

3

You can connect the component to your Redux store using connect from react-redux.

App.js

import { Provider } from 'react-redux'

// ... rest of code ...

class App extends Component {
    render() {
        return (
            // Set up a provider context
            <Provider store={store}>
                <div className="App container-fluid">
                    <div className="row text-center">
                        <div className="col-3"><LoginApi/></div>
                    </div>
                </div>
            </Provider>
        );
    }
}

LoginApi.js

import React from 'react';
// Import connect
import { connect } from 'react-redux';
import './LoginApi.css';

class LoginApi extends React.Component {
    handleLogout() {
        // We get ``dispatch`` through props now
        this.props.dispatch({ type: "LOGOUT"});
    }

    handleLogin() {
        // We get ``dispatch`` through props now
        this.props.dispatch({ type: "LOGIN", sessionToken, isLoggedIn: true, group });
    }

    render() {
        // Access the props here
        const { sessionToken, isLoggedIn } = this.props;

        return (
            <div className="Login">
                {(isLoggedIn === true && sessionToken !== "") ?
                    <button type="button" className="btn btn-danger" onClick={this.handleLogout}>Logout</button>
                    :
                    <button type="button" className="btn btn-primary" onClick={this.handleLogin}>Login</button>
                }
            </div>
        );
    }
}

// This allows you to control how your Redux store
// is mapped to this component's props.
const mapStateToProps = (state) => {
    const { isLoggedIn, sessionToken } = state;

    return {
        sessionToken,
        isLoggedIn,
    };
};

// Wrap your export with connect and pass it mapStateToProps
export default connect(mapStateToProps)(LoginApi);

This setup will allow you to access the Redux state from any component that you export with connect rather than passing store directly through props to each component.

Note: you also get dispatch through props so the lines this.props.store.dispatch can be reduced to this.props.dispatch.

Sign up to request clarification or add additional context in comments.

5 Comments

This won't work unless you also set up a <Provider> context for the store, which isn't currently happening - the store gets passed in as a prop and then dispatch is called directly. Also need to set up the action properly so the action is dispatched properly.
It depends on react-redux version. Some versions had support for passing store through props without Provider.
@DuncanThacker Yeah I forgot to add that on the first post, cheers for pointing that out.
Well ! Thank you it worked. Thank you for the tutorial.
No worries, glad to help.
1

You probably meant default: return state;. Otherwise any action except 'LOGIN' and 'LOGOUT' will set your login state to something unexpected (usually undefined).

To trigger a rerender you need to update props or internal state of the component. You need to subcribe to your store and do it manually or use connect.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.