reactjsreact-reduxreactjs-flux

How to communicate between react service and a component?


I had created a util .js file that calling rest api's, and I need to communicate between this util (not a component) and other components.

For example, when doing login if it fails to raise an event that Login component will catch and act accordingly.

Not sure if it's the right approach (I'm new to react), how it can be done?


Solution

  • I implemented a flux solution (despite a redux appraoch could be enough and one store -which is the rest service- can do the work)

    Dispatcher:

     import { Dispatcher } from 'flux';
    
    export default new Dispatcher();
    

    RestService (store):

    import React, {Component} from 'react';
    import ReactDOM from 'react-dom';
    import App from '../App';
    
    import {EventEmitter} from 'events';
    import dispatcher from '../Dispatcher';
    import * as Actions from "../actions/Actions";
    
    const baseUrl = 'http:/.../WebServices/api';
    
    class ApiService extends EventEmitter {
    
        constructor() {
            super();
    
            this.updateStatus = this.updateStatus.bind(this);
    
            this.state = {
                loginFailed: false
            }
        }
    
        getLoginStatus() {
            return this.state.loginFailed;
        }
    
        updateStatus(status) {
            //this.setState({loginFailed: true});
            this.state.loginFailed = status;
        }
    
        // module.exports = {
    
            /*export function*/ login(userName, password) {
                fetch(baseUrl + '/SessionManager/login?userName='
                    + userName + '&password=' + password,
                    {
                        //method: 'GET',
                        //credentials: "same-origin",
                        //mode: "no-cors",
                        //headers: headers
                        //'Content-Type': 'application/json'
                    }
                ).then(
                    (response) => {
                        localStorage.setItem('Response', JSON.stringify(response))
                        //console.log("Headers ======>", JSON.stringify(response.headers));
    
                        // Inspect the headers in the response
                        response.headers.forEach(console.log);
                        // OR you can do this
                        for (let entry of response.headers.entries()) {
                            console.log(entry);
                        }
    
                        // let sid = getSessionCookie(); //document.cookie.match('sid=([^;]*)');
                        // console.log("Session Id: ", sid);
                        // localStorage.setItem('session', sid)
    
                        // let headers = response.headers.get('Set-Cookie')
                        // console.log("Headers: ", headers);
                        // localStorage.setItem('headers', headers)
    
                        if (response.status < 200 || response.status > 300) {
                            // console.log('Looks like there was a problem. Status Code: ' + response.status);
                            // this.state.showError = true;
                            // this.state.errorMessage = 'Please enter a valid credentials.';
    
                            //this.setState({loginFailed: true});
                            this.updateStatus(true);
                            this.emit("statusChanged", response);
    
                            return;
                        } else {
                            //window.location.href = '/main';
                            ReactDOM.render(<App user={userName}/>,
                                document.getElementById('root'));
                        }
    
                        // Examine the text in the response
                        // response.json().then(function(data) {
                        //     console.log(data);
                        // });
                    }
                ).catch((error) => {
                    console.error(error);
                });
            }
    
            /*export function*/ getProjectDetails() {
                //let params = this.getSession();
                //console.log('Params....', params);
    
    
                fetch(baseUrl + '/ProjectManager/getProjectDetails',
                    {
                        //   //credentials: "include",
                        //   //credentials: "same-origin",
                        //   //crossdomain: true,
                        //   //mode: 'no-cors',
                        //headers: headers
                    }
                )
                    .then(res => res.json())
                    .then((data) => {
                        this.setState({projectsDetails: data})
                        console.log(data);
                    })
                    .catch(console.log);
            }
        // }
    
        handleActions(action) {
            switch(action.type) {
                case "LOGIN": {
                    this.login(action.user, action.password);
                    //this.emit("change");
                }
                // case "LOGIN_FAILURE": {
                //     this.setState({loginFailed: true});
                //     this.emit("change");
                // }
            }
        }
    }
    
    // const service = new ApiService();
    // // Register dispatcher
    // dispatcher.register(service.handleActions.bind(service));
    // // Expose dispatcher globally
    // window.dispatcher = dispatcher;
    
    export default ApiService;
    

    Actions :

    import dispatcher from '../Dispatcher';
    
    export function login(user, password) {
    
        dispatcher.dispatch({
            type: "LOGIN",
            user: user,
            password: password
        })
    
    }
    

    Login component:

    import React, { Component } from 'react';
    import {Button, Form, TextInput} from 'carbon-components-react';
    import './Login.css';
    //import * as service from  '../services/RestService.js';
    import ApiService from '../stores/RestService.js';
    import ReactDOM from "react-dom";
    import App from "../App";
    import * as Actions from "../actions/Actions";
    import dispatcher from "../Dispatcher";
    
    
    const apiService = new ApiService();
    
    // Register dispatcher
    dispatcher.register(apiService.handleActions.bind(apiService));
    // Expose dispatcher globally
    window.dispatcher = dispatcher;
    
    
    class Login extends Component {
    
        //errorMessage;
        service;
        getLoginStatus;
    
        constructor(props) {
            super(props);
            this.getLoginStatus = this.getLoginStatus.bind(this);
    
            //this.service = new ApiService();
            this.state = {
                userName: '',
                password: '',
                // errorMessage: '',
                //showError: false,
                loginFailed: false
            }
    
            apiService.on('statusChanged', this.getLoginStatus);
        }
    
        componentWillMount() {
            apiService.on('change', this.getLoginStatus);
        }
    
        componentWillUnmount() {
            apiService.removeListener("change", this.getLoginStatus);
        }
    
        getLoginStatus() {
            this.setState({
                loginFailed: apiService.getLoginStatus()
            });
        }
    
        handleUserChange(e) {
            this.setState({ userName: e.target.value });
        }
    
        handlePasswordChange(e) {
            this.setState({ password: e.target.value });
        }
    
        handleSubmit = (event) => {
            event.preventDefault();
    
            //this.service.login(this.state.userName, this.state.password);
            Actions.login(this.state.userName, this.state.password);
        }
    
    
        render() {
            const {loginFailed} = this.state;
            return (
                <div className="App">
                    <header className="App-header">
    
                        <table width="100%" className="Toolbar1">
                            <tbody>
                            <tr>
                                <td width="90%">
                                    <h2>My App</h2>
                                </td>
                                <td>
                                    <Button className="button">
                                        Help
                                    </Button>
                                </td>
                            </tr>
                            </tbody>
                        </table>
    
                    </header>
    
                    <body classname="App-body">
                        <table width="25%" align="center" className="bordered spaced centered">
                            <tbody>
                            <tr>
                                <td width="75%">Welcome to ...</td>
                                <td>Ver: 1.0.0</td>
                            </tr>
                            <tr>
                                <td colSpan="2">
                                    <Form onSubmit={this.handleSubmit}>
                                            <TextInput
                                                className="wide"
                                                id="txtUser"
                                                labelText=""
                                                placeholder="User Name"
                                                required
                                                onChange={ this.handleUserChange.bind(this) }
                                            />
                                            <br/>
                                            <TextInput
                                                className="wide"
                                                id="txtPassword"
                                                type="password"
                                                required
                                                labelText=""
                                                placeholder="Password"
                                                // pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}"
                                                // {...InvalidPasswordProps}
                                                required
                                                onChange={ this.handlePasswordChange.bind(this)}
                                            />
                                            <br/>
                                            <Button type="submit" className="button wide"
                                                    //onSubmit={this.handleSubmit}
                                                    //onClick={this.handleClick}
                                            >
                                                Login
                                            </Button>
                                        <br/><br/>
                                    </Form>
                                </td>
                            </tr>
                            </tbody>
                        </table>
    
                        {/*<spane style={{color: 'red'}}><b>Please enter valid credentials.</b></spane>*/}
                        <div style={{color: 'red'}} className="alert alert-danger centered2">
                            { loginFailed ? <span color="Red"><strong>Error!</strong> Please enter valid credentials.</span> : null }
                        </div>
                    </body>
    
                    <footer>
    
                    </footer>
    
                </div>
            );
        }
    }
    
    export default Login;