Nicolas Taboada
Nicolas Taboada

Reputation: 81

React-Redux / Child component not re-rendering

I am doing my first steps with React-Redux together. I am having troubles with the state managing.

Everything is working as expected. I have a button that onClick triggers the action dispatcher (FetchUserAction). This action does an HTTP request. Reducer consumes the data and modifies the store. I was debugging and saw that on connect function the state (with the data) is coming well.

My understanding is when the state is modified, the component is going to call the render method. That is happening! The real problem is that I expect that as I pass the new data through prop to the child component I will see it, but that is not occurring. What am I doing wrong?

class Home extends Component {

    constructor(props) {
        super(props);
        this.state = {
            users: []
        };
        this.onButtonUserClick = this.onButtonUserClick.bind(this);
    }


    onButtonUserClick(){
        this.props.fetchUser();
    }

    render() {
        return (
                <div className={styles.home}>
                    <FetchUsersButton
                        fetchUsers={this.onButtonUserClick}/>
                    <UsersTable
                        users={this.props.users}/>
                </div>
        );
    }

}

function mapDispatchToProps(dispatch) {
    return bindActionCreators({ fetchUser }, dispatch);
}

const mapStateToProps = (state) => {
    return {
        users: state.users
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(Home);

import React, {Component} from 'react';
import {Table, Thead, TBody, Td, Th, Tr} from 'reactable';

import styles from './index.css';

export default class UsersTable extends Component{

    constructor(props){
            super(props);
            this.state = {
                users: props.users
            };
            this.renderUsersTable = this.renderUsersTable.bind(this);
    }

    renderUsersTable() {
        return this.state.users.map(user => {
            return (
                <Tr key={user}>
                    <Td column="steamId">
                        {user.steam_id_64}
                    </Td>
                    <Td column="invited">
                        Yes
                    </Td>
                </Tr>
            );
        });
    }

    render(){
        return(
            <Table className={`table ${styles.usersTable}`}>
                    <Thead>
                    <Th column="steamId">
                            <strong className="name-header">SteamID</strong>
                    </Th>
                    <Th column="invited">
                            <strong>Invited</strong>
                    </Th>
                    </Thead>
                    { this.state.users.length > 0 ? this.renderUsersTable() : null}
            </Table>
        );
    }
}

import { FETCH_USERS } from "../actions/index";

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

Upvotes: 0

Views: 753

Answers (1)

Kyle Richardson
Kyle Richardson

Reputation: 5645

Your <UserList /> rendering is looking to it's internal state for what to render. You will need it to look at props for this to work.

renderUsersTable() {

        // change this.state to this.props
        return this.state.users.map(user => {
            return (
                <Tr key={user}>
                    <Td column="steamId">
                        {user.steam_id_64}
                    </Td>
                    <Td column="invited">
                        Yes
                    </Td>
                </Tr>
            );
        });
    }

Fix this line to reference props as well { this.state.users.length > 0 ? this.renderUsersTable() : null}

Side note: You could turn <UserList /> into a stateless functional component and get rid of the class overhead.

Upvotes: 2

Related Questions