0

I have a modal for login dialog that is triggered by clicking a non-react component.

I managed to dispatch the action and update the state when the non-react component is clicked, so the information is available on props, but I need to trigger a function that updates CSS and such, and that I could not do inside the container.

That would be trivial if the action was coming from the container or its children.

So, on the app.js code below, I am trying to trigger the method onLoginClick() whenever the SHOW_LOGIN action is dispatched.

Also, this.state.message should be updated with the payload of SHOW_LOGIN on that same onLoginClick() method.

Redux's store.subscriber() method is triggered on changes to state, but I could not find out how to make it work in this situation.

First, it is only available on the upstream component and then I still cannot trigger the onLoginClick() method from store.subscriber.

Thanks

non-react element utils.js

`//react files to enable #signin_button to activate popup

import { dispatch } from 'redux';
import { showLogin } from '../../client/login/actions/';
import { store } from '../../client/login/';

$("#signin_button").click(function(e) {
store.dispatch(showLogin());
.......`

/login/actions/index.js

export const SHOW_LOGIN = 'SHOW_LOGIN';

export function showLogin(){
  return {
    type: SHOW_LOGIN,
    payload: 'some text'
  }
}

/login/reducers/reducer_login.js

import { SHOW_LOGIN } from '../actions/index';

export default function (state = [], action){
    switch (action.type) {
        case SHOW_LOGIN:
            return [ ...state, action.payload ];
    }
   return state;
}

/login/reducers/index.js

import { combineReducers } from 'redux';
import LoginReducer from './reducer_login';
import RecoveryReducer from './reducer_recovery';
import SubmitRecoveryReducer from './reducer_submit_recovery';

const rootReducer = combineReducers({
    login: LoginReducer,
    recovery: RecoveryReducer,
    submit_recover: SubmitRecoveryReducer
});

export default rootReducer;

/login/containers/app.js

import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { showLogin, showRecovery, submitRecovery } from '../actions/index';
import Recovery from './recovery';
import SocialLogin from './social_login';

class LoginPopup extends React.Component{

    constructor(props){
       super(props);
       this.state = { 
         error : false, 
         emailRecovery:  '',
         message: 'some message'
      };
      this.recovery = this.recovery.bind(this);
      this.onRecoveryChange = this.onRecoveryChange.bind(this);
      this.onSubmitRecovery = this.onSubmitRecovery.bind(this);
   }
recovery() {
  //handles showing recovery password dialog 
}

onRecoveryChange(event){
    this.setState({emailRecovery: event.target.value});
}

onSubmitRecovery(event){
   //handles recovery password request
}

onLoginClick(){
   //*** handles CSS and other when non-react component clicked ***
}

render(){
    console.log(this.props.login);

    return (
        <div id="popup_sign" style={{display:'none'}} >
            <h4 className="account_notice">
                {this.state.message}
            </h4>
            <div id="login">
                <SocialLogin error={this.state.error} recovery={this.recovery}/>
                <button id="ok_login"  className="sub_ok btn btn-sm" type="button" >OK</button>
            </div>
            <Recovery 
                submitRecovery={this.onSubmitRecovery} 
                email={this.state.emailRecovery}
                emailChange={this.onRecoveryChange} />
        </div>
    )
}

const mapStateToProps = (state) => {
    return {
       login: state.login,
       recovery: state.recovery,
        submit_recover: state.submit_recover
    }
}

function mapDispatchToProps(dispatch){
    return bindActionCreators({ showLogin,showRecovery,submitRecovery }, dispatch);
}
6
  • Have redux assign dispatch to your component as usual, and from your non react code, call a method that calls dispatch Commented Feb 10, 2018 at 9:45
  • Thanks @AbderrahmaneTAHRIJOUTI, but I think that's already done on utils.js above. As said, the action is dispatched and also received on app.js. The question is how to trigger the onLoginClick method whenever that action is dispatched from utils.js Commented Feb 10, 2018 at 9:55
  • Adding a lifecycle method like componentDidMount() {} containing $("#signin_button").addEventListener('click', this.onLoginClick.bind(this)) and additional listeners as needed? Commented Feb 10, 2018 at 12:07
  • @RikkuBölske, Perfect, that will do it. I only changed to plain js using document.getElementById("signin_button"). Please, put this up as an answer so that I can accept it propertly. Much appreciated. Commented Feb 10, 2018 at 12:52
  • @RikkuBölske. That works, but it occurred to me that what's triggering the onLoginClick() is not the change of Redux state but rather the click event itself. Not sure if that's not going to cause some race condition. Commented Feb 10, 2018 at 13:00

1 Answer 1

1
componentWillReceiveProps(nextProps) {
  this.onLoginClick(nextProps);
}

onLoginClick (nextProps) {
    if (nextProps.login.length > this.props.login.length) {
        this.setState({message: nextProps.login});
        $("#popup_sign").show();
}
Sign up to request clarification or add additional context in comments.

6 Comments

Ok, I believe I have it figured out. The life cycle method that should be used is actually componentWillReceiveProps(nextProps). It's the one that captures changes in props and where one can use this.setState(). It looks like this: componentWillReceiveProps(nextProps) { this.onLoginClick(nextProps); } . Then ` onLoginClick (nextProps) {//do stuff}`.
If you would like, please adapt your answer to above so that I can accept it. You put me on the right track. Thanks.
The componentDidMount is not needed. I edited your answer awaiting review.
Oh. Did you move const nonReactBtn = document.getElementById("signin_button"); nonReactBtn.addEventListener('click', showLogin); to somewhere else? I think that should at least be reflected in the answer (as the original question was about this)
That's not at all necessary. componentWillReceiveProps() is triggered when props change. So, whenever the user clicks on signin_button the action is dispatched as per utils. js above. Then, when the props change to reflect that, componentWillReceiveProps is automatically triggered by React. That was the hook I needed to call the onLoginClick method. I was not looking to attach anything on the click event, but rather on the normal props change. Take a look in the documentation [link] (reactjs.org/docs/react-component.html#componentwillreceiveprops)
|

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.