1

I am starting with typescript and react redux. I have a login component which in turns has it's action creator which dispatch the LOGIN_SUCCESS action:

export const actionCreators = {
    loginRequest: (user:string): AppThunkAction<KnownAction> => (dispatch, getState) => {
         userService.login(JSON.parse(user))
         .then(
             (data)=>{//ok
                dispatch({ type: 'LOGIN_SUCCESS', success: true, message: data });    

            },
            (data)=>{//error
                toast.error(""+data)
            }
        );

        dispatch({ type: 'LOGIN_REQUEST' });
    },
...
};

then on the reducer:

export const reducer: Reducer<LoginState> = (state: LoginState, action: KnownAction) => {
    switch (action.type) {
        case 'LOGIN_REQUEST':
            return {... state};
        case 'LOGIN_SUCCESS':
            return {... state ,success:action.success, message:action.message};
        case 'LOGIN_FAILURE':
            ...
        default:
            ...
    }

   ...
};

I am updating the state. Then I expect that in the component:

componentWillReceiveProps(newProps: LoginProps){
        console.log(newProps);
        if(newProps.success){
            this.props.history.push('/home')
        }
    }

it will receive the new props and push me to /home, but nothing happens. I have setted a console.log(newProps) to check when it gets the new properties, but it's never hitted. Can anyone help me? Any help would be much appreciated.

EDIT

this is how i got them connected:

export default connect(
    (state: ApplicationState) => state.login, // Selects which state properties are merged into the component's props
    loginState.actionCreators                 // Selects which action creators are merged into the component's props
  )(Login) as typeof Login;
  • 1
    Is your component being connected to your `LoginState`? A prop update will only be triggered if there are actually props to update. – casieber Jan 17 '18 at 19:17
  • Is your component connected to the store? (Are you calling [`connect`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) from the Redux API?) – Ross Allen Jan 17 '18 at 19:17
  • I have edited the question. I am using connect in the component – Oscar Cabrera Rodríguez Jan 17 '18 at 19:22

2 Answers2

0

You need to return an object from the first argument of connect

export default connect(
    (state: ApplicationState) => ({signup: state.signup}), // Selects which state properties are merged into the component's props
    loginState.actionCreators                 // Selects which action creators are merged into the component's props
  )(Login) as typeof Login;

and then use it as

componentWillReceiveProps(newProps: LoginProps){
    console.log(newProps);
    if(newProps.signup.success){
        this.props.history.push('/home')
    }
}

assuming the router props are available to the component, if not check this

Shubham Khatri
  • 211,155
  • 45
  • 305
  • 318
0

An alternative option would to instead use react-router-dom <Redirect /> to redirect to "/home" when signup.success merged into props from the Redux store is true/truthy:

{this.props.signup && this.props.signup.success &&
    <Redirect to="/home" />
}

As your Login component is connected to the Redux store, you can simply listen/watch the mapStateToProps values rather than needing the Component life cycle hooks.

If you do utilize this approach, you'd need to likely wrap your connected Login component with withRouter:

export default withRouter(connect(
    (state: ApplicationState) => ({signup: state.signup}), 
    loginState.actionCreators
  )(Login)) as typeof Login;

Hopefully that helps.

Thanks!

Alexander Staroselsky
  • 28,923
  • 8
  • 58
  • 75
  • this line is giving me trouble(state: ApplicationState) => ({signup: state.signup}). When I add ({signup: state.signup}), then ...(Login)) as typeof Login is thowing an error. perhaps I have to add something to the state? – Oscar Cabrera Rodríguez Jan 17 '18 at 19:51
  • It must be a compiler error due to TypeScript. I'm not 100% sure how the exported element would need to be typed to avoid the compiler error, but the `` is an approach can be taken to redirect accordingly based on a conditional property. Without TypeScript it basically looks like `export default withRouter(connect(...)(Login))` – Alexander Staroselsky Jan 17 '18 at 19:52
  • the editor is complaining about this: Type 'typeof Login' provides no match for the signature '(props: { signup: SignupState; }& { children?: ReactNode; }, context?: any): ReactElement | null' – Oscar Cabrera Rodríguez Jan 17 '18 at 19:57
  • do I still need mapStateToProps, eve if i did the connect in the way exposed above? – Oscar Cabrera Rodríguez Jan 17 '18 at 20:10
  • You are using mapStateToProps in your example, that's just the function that's passed into 1st argument of `connect()`. You are already successfully mapping/merging values into the component props. The argument is referred to as `mapStateToProps` in the react-redux documentation. – Alexander Staroselsky Jan 17 '18 at 20:18
  • yo know, in the way i was doing it(componentWillReceiveProps did not work, though) I was able to see the success property being set to true in the redux dev tools, but the componentWillReceiveProps did not got triggered – Oscar Cabrera Rodríguez Jan 17 '18 at 20:29
  • This may be an issue with the mapStateToProps function. Try logging/inspecting what's returned from `state` within that function where you return `({signup: state.signup})`. Make sure you are retrieving `signup` and returning `signup` effectively. If you are seeing action 'LOGIN_SUCCESS' it could be an issue with what's being returned in that mapStateToProps function. – Alexander Staroselsky Jan 17 '18 at 20:41
  • Never mind. I did exactly as you said and It worked. After hours banging my head against the wall i discovered i had a typo: I was referring to the signup state, but the state I was really changing was the login. thank you very much for yor time – Oscar Cabrera Rodríguez Jan 17 '18 at 21:14
  • Glad to help and glad to hear the issue was resolved! It comes down to what the states of each reducer in something like `combineReducers()` are namespaced as using the passed in keys. Please make sure to mark the answer that assisted in the resolution. Thanks! – Alexander Staroselsky Jan 17 '18 at 21:45