tolga
tolga

Reputation: 2800

Passing new state to child component in React

I connected Home component props with action method and dispatch the reducer successfuly. All seems to work fine, I can see Api data coming to reducer in console.

Problem is, react doesn't re-render ProfileGroupsWidget. this.props.user is always {} in this child component, I was expecting it to be {name: "John Doe"}

Here is userReducer, "GET_AUTH_USER_SUCCESS" comes from getAuthenticatedUser:

const initialState = {};

const userReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'GET_AUTH_USER_SUCCESS':
            console.log('Output:', action.user); // {name: "John Doe"}
            state = action.user
            return state;
        default:
            return state
    }
}

export {userReducer}

Home is my Home component:

import React, { Component } from 'react';
import ProfileGroupsWidget from './Widgets/ProfileGroupsWidget.js'
import {connect} from 'react-redux'
import {userActions} from "../_actions/userActions";

class Home extends Component{

    constructor(props) {
        super(props);
        this.state = {
            user: this.props.user
        }
        this.props.getAuthenticatedUser();
    }

    render() {
        return (
            <ProfileGroupsWidget user={this.state.user}></ProfileGroupsWidget>
        )
    }

}

const mapStateToProps = state => {
    return state
}

function mapDispatchToProps(dispatch){
    return {
        getAuthenticatedUser : () => {dispatch(userActions.getAuthenticatedUser())}
    }
}

// Connect Home component props with store data:
export default connect(mapStateToProps, mapDispatchToProps)(Home);

Upvotes: 1

Views: 53

Answers (2)

Tyro Hunter
Tyro Hunter

Reputation: 755

Why are you passing props.user to your state? That should be unnecessary based on your current code. With that, it would be better to assign this.props.user directly to ProfileGroupsWidget. That is if your redux is working and connected properly to your component.

Another thing here (Calling action from constructor vs a life cycle method), it's better to call network requests or actions inside componentDidMount rather than in your constructor:

componentDidMount() {
  this.props.getAuthenticatedUser();
}

If you have everything correct you should see multiple console.logs of this.props.user if you log it inside render():

render() {
  console.log(this.props.user);
  /*
    should be called at least twice,
    the last one containing the data {name: "John Doe"}
  */

  return (
    <ProfileGroupsWidget user={this.props.user}></ProfileGroupsWidget>
  )
  ...

Upvotes: 2

Avanthika
Avanthika

Reputation: 4182

In your code, this.props.user will always be undefined because you are not setting the value for it in the reducer. We have to set the value in the following way:

Edited Code:

const initialState = {
 user: {}
};

const userReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'GET_AUTH_USER_SUCCESS':
           return { ...state, user: action.user };
        default:
            return state;
    }
}

export { userReducer }

Edited Code: In home component: (in mapStateToProps, I have maintained userReducer as identifier, please change it to whatever reducer name you have used in the rootReducer).

We can also remove the constructor code entirely if you like, and move the action dispatch to componentWillMount().

import React, { Component } from 'react';
import ProfileGroupsWidget from './Widgets/ProfileGroupsWidget.js'
import { connect } from 'react-redux'
import { userActions } from "../_actions/userActions";

class Home extends Component{
    constructor(props) {
        super(props);
        this.state = {
          user: props.user
        }
        props.getAuthenticatedUser();
    }

    render() {
        return (
            <ProfileGroupsWidget user={this.props.user}></ProfileGroupsWidget>
        )
    }
}

const mapStateToProps = state => ({
   user: state.userReducer.user
});

const mapDispatchToProps = (dispatch) => ({
  getAuthenticatedUser: () => dispatch(userActions.getAuthenticatedUser())
});

// Connect Home component props with store data:
export default connect(mapStateToProps, mapDispatchToProps)(Home);

Upvotes: 2

Related Questions