zameb
zameb

Reputation: 840

React-Redux: State is empty during connect

There are similar questions, but the solutions are not working for me. I cannot see where we instruct React-Redux to put some value on the state. In the following component this part fails (state) => ({ ingredients: state.ingredients }). The reason: state is undefined

import React from 'react';
import { connect } from 'react-redux'

class Ingredients extends React.Component {

    render() {
        return (
            <div>Ingredients</div>
        );
    }
}

export default connect(
    (state) => ({ ingredients: state.ingredients }),  //This fails!
    (dispatch) => ({ 
        createNew: () => dispatch(actions.createNew()), 
        edit: (id) => dispatch(actions.edit(id)) 
    })
)(Ingredients);

The store simply has:

function AppStore(state, action) {
        return { 
            ingredients: { foo: "bar" } 
        };
    }
}

export default AppStore;

There is no way for ingredients to be empty

The Store is binded to the App as:

var appStore = createStore(AppStore);

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

The App component is just a view which contains the component (ingredients) that I really need to have with redux:

class App extends React.Component {
    render() {
        return (
            <div>
                <Header/>
                <Switch>
                    <Route path='/home' component={Home} />
                    <Route path='/recipes' component={Recipes} />
                    <Route path='/ingredients' component={Ingredients} />
                    <Route render={() => <div>Not found!</div>} />
                </Switch>
                <Footer />
            </div>
    );
  }

The Ingredients component is the one at the start of my post. I feel like this Redux magic is missing pieces or it is really counter-intuitive.

How Ingredients component could know the value of "state"? Where is it injected to the component? How Redux would know on which components to inject the state?

I have follow different tutorials and in all of these I can only see createStore is caled, then its assigned to a tag and then "connect" is used to export the component. Is it normal for me too feel very unconfortable with this kind of setup? First I feel bad after accepting React as a "component oriented" way of work to end having all the logic in a single store. Also, I question why the "connect" implementation, when we can have component inheritance (what about extend Redux.ConnectedComponent or something like that?)... Then, all this magical setup... maybe I should try other thing instead of Redux?

EDIT: changed the connect part as:

function mapStateToProps(state) {
    return { ingredients: state.ingredients };
}

function mapDispatchToProps(dispatch) {
    return {
        createNew: () => dispatch(actions.createNew()), 
        edit: (id) => dispatch(actions.edit(id)) 
    };
}

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

With this change (just reordered syntax I think), the state is undefined

EDIT 2: My fault, I was importing a different store to the one shown here If I import the correct one, the state is no longer undefined

Upvotes: 1

Views: 798

Answers (1)

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

Common practice is to create a separate mapStateToProps function that returns an object, defining a key-value pair for each piece of redux-state you want to make available as a prop in your component.

This will simplify your connect logic significantly.

import React from 'react';
import { connect } from 'react-redux'

class Ingredients extends React.Component {

    render() {
        return (
            <div>{this.props.ingredients.foo}</div>
        );
    }
}

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

export default connect(mapStateToProps, { createNew, edit })(Ingredients)

The connect function will hook the store's state object to the function(s) that was passed as the first argument. Similarly you could do the same with your dispatcher functions, using ES6 to pass them in as an object. The dispatch method then gets passed to each of those functions in the 2nd argument.

Upvotes: 1

Related Questions