user359698
user359698

Reputation: 193

React-redux connect() fails to pass the props

I'm trying to learn react-redux architecture, and I failed on the most basic stuff.

I created class HomePage and used react-redux connect() to connect it to store's state and dispatch.

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {HomeButtonClickAction} from "./HomeActionReducer";
import {connect} from "react-redux";

class HomePage extends Component {

    constructor(props) {
        super(props);

        console.log('HomePage props');
        console.log(this.props);

        this.buttonClicked = this.buttonClicked.bind(this);
    }

    buttonClicked() {
        console.log('button cliked');
        this.props.buttonClick();
    }

    render() {
        console.log('Re-rendering...');

        let toggleState = this.props.toggle ? 'ON' : 'OFF';
        return (
            <div>
                <button onClick={this.buttonClicked}>{ toggleState }</button>
            </div>
        )
    }
}

HomePage.propTypes = {
    toggle: PropTypes.bool.isRequired,
    onClick: PropTypes.func.isRequired
};

const mapStateToProps = (state, ownProps) => {
    return {
        toggle: state.toggle
    }
};

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        buttonClick: () => {
            dispatch(HomeButtonClickAction());
        }
    }
};

const HomeContainer = connect(
    mapStateToProps,
    mapDispatchToProps
)(HomePage);

export default HomePage;

But it's not working for me. HomeContainer doesn't pass props to HomePage component. I've got these warnings in devtools.

enter image description here

My index.js looks like this.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import AppReducer from "./reducers/AppReducer";
import { createStore } from "redux";
import { Provider } from 'react-redux';

const store = createStore(AppReducer);

ReactDOM.render(
    <Provider store={ store }>
        <App/>
    </Provider>,
    document.getElementById('root')
);

registerServiceWorker();

and AppReducer.js

import { combineReducers } from 'redux';
import { toggle } from '../home/HomeActionReducer';

const AppReducer = combineReducers({
    toggle
});

export default AppReducer;

and HomeActionReducer.js

const HOME_BUTTON_CLICK = 'HOME_BUTTON_CLICK';

export function toggle (state = true, action) {
    console.log('toggle launched');

    switch (action.type) {
        case HOME_BUTTON_CLICK :
            return !state;

        default:
            console.log('Toggle reducer default action');
            return state;
    }
}

export function HomeButtonClickAction() {
    console.log('action emitted');

    return {
        type: HOME_BUTTON_CLICK
    };
}

Being a newbie I'll really appreciate your help :)

Upvotes: 3

Views: 3592

Answers (2)

Daniel
Daniel

Reputation: 15393

You have this:

const HomeContainer = connect(
    mapStateToProps,
    mapDispatchToProps
)(HomePage);

export default HomePage;

To create an instance of the connect component you need to do this:

export default connect()(HomePage);

Notice I did not write export default twice, bad practice, you only export default once per component so the connect() goes inside that same line of code and the invocation or second set of parentheses you wrap around the component you are working in.

This connect() function is actually a React component that you are going to pass some configuration to and the way you begin to do that is by calling mapStateToProps like so:

const mapStateToProps = () => {

};

export default connect()(HomePage);

You could also do:

function mapStateToProps() {

}

If you read it, it makes sense, this is saying that we are going to map our state object, all the data inside the redux store and run some computation that will cause that data to show up as props inside our component, so thats the meaning of mapStateToProps.

Technically, we can call it anything we want, it does not have to be mapStateToProps, but by convention we usually call it mapStateToProps and its going to be called with all the state inside of the redux store.

const mapStateToProps = (state) => {

};

export default connect()(HomePage);

The state object contains whatever data you are trying to access from the redux store. You can verify this by console logging state inside the function like so:

const mapStateToProps = (state) => {
  console.log(state);

   return state;
};

export default connect()(HomePage);

I am returning state just to ensure that everything is working just fine.

After defining that function, you take it and pass it as the first argument to the connect() component like so:

const mapStateToProps = (state) => {
  console.log(state);

   return state;
};

export default connect(mapStateToProps)(HomePage);

Thats how we configure the connect component.We configure it by passing it a function. Run that and see what happens.

Upvotes: 0

GG.
GG.

Reputation: 21834

You are exporting HomePage, which is the presentational component. You want to export HomeContainer, which is the container that passes the props to HomePage through connect.

So replace this

export default HomePage;

with this

export default HomeContainer;

You can also directly write

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

Note that, since it's the default export, you can name the import as you want, eg.:

import HomePage from './HomePage' // even if it's HomeContainer that is exported

Upvotes: 5

Related Questions