Sign in Go Pro

React Native with Redux

Accessing the Store with Redux Connect

 
Autoplay

Up next

Previous

About

Hooking up a component to the Redux store is called "connecting" that component. Connect can be used to pull data from the redux store, or can change data in the store by dispatching actions to it. We'll pull the list of todo items from the store with mapStateToProps, and display them on the todo list screen.

Summary of Content:

  • Connect the todo list component to the redux store
  • Use the mapStateToProps function to add props to the TodoList component
  • Pull the todos items from the redux store in mapStateToProps
  • Change the render method of the TodoList component to read from the redux store

Instructor

Links

Comments

Following your tutorial to this stage.
Not using your starter ToDo template, but my own existing starter project integrating the following: 'react-native-vector-icons/Ionicons', 'react-native', "react-native-elements", 'react-navigation', 'react-navigation-stack', 'react-navigation-tabs', 'react-redux', 'redux'.
All appears to be working until I got to this section.
The problem is my existing code, which is from a working tabBar & navigation code base, the default doesn't appear to be a Component as your tutorial uses.
Here it is:
export default createAppContainer(
createBottomTabNavigator(
{
Home: HomeStack,
Settings: SettingsStack,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) =>
getTabBarIcon(navigation, focused, tintColor),
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
}
)
);

Now I ran into an earlier problem when trying to add the Provider code to this main function, so I got it to work by adding it to the Render() part of the HomeScreen tab Component:
return(
Provider store={store}>
View style={{flex: 1, padding: 10, top: 30}}>
FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
/>
/View>
/Provider>
);

But I feel this might not have been the best place to place the Provider code even though it worked.
I suspect that since I am not familiar with what I am doing that my attempts are further complicating the process, so I am reaching out to you for help.

So, to recap, my specific problem is converting the above "export default createAppContainer" to use your tutorial code "export default connect()"

You want to put the Provider component at the highest level possible in the component stack, so that you can have access to the redux store from all components in that tree.

If I understand correctly, then while you did get it to work by adding it to the home screen - adding it there means you won't be able to access that store from any other component.

Instead, perhaps try something like this:

const AppContainer = createAppContainer(....
...)

<Provider store={store}>
<AppContainer />
</Provider>

EDIT: [sorry, formating isn't working very well - trying to figure it out :) ]

Then, you'll be able to connect any of those child components (like HomeStack, etc)

Does that make sense with what you're describing? Or am I misunderstanding what you're trying to do?

I had mentioned 2 issues.
The 1st issue was solved by your recommendation.
Here is the working code:
const AppContainer = createAppContainer(
createBottomTabNavigator(
{
Home: HomeStack,
Settings: SettingsStack,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) =>
getTabBarIcon(navigation, focused, tintColor),
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
}
)
);

export default class App extends React.Component {
render() {
return (
Provider store={store}>
AppContainer />
/Provider>
)
}
}

Now I am struggling with the 2nd issue that is still unresolved.
After importing connect, I have removed "export default" from the "class App" (as shown above).
I have added the following code (note that I have replaced your todos with my initialList):
const mapStateToProps = (state, ownProps) => {
return {
items: state.initialList.items
}
}
export default connect(mapStateToProps)(App)

This results in an error:
Could not find "store" in the context of "Connect(App)". Either wrap the root component in a , or pass a custom React context provider to and the corresponding React context consumer to Connect(App) in connect options.

This error is located at:
in ConnectFunction (at renderApplication.js:40)

ah yes, ok - so the App component is the one that you put the Provider in, which means you won't be able to connect the App component itself.

Instead, you'll be able to wrap any child (or grandchild, etc) component of App. Does that make sense?

So normally, App is just a simple component that contains the provider, and then the AppContainer (like you have it) - and you don't have to connect it; instead, try to connect the other components in your tree.

Yes, that is starting to make sense, thank you.
Now I just need an example of how to code this child component of App.
In my existing code I just have everything in App.js, except for your tutorial code for adding the 2 files "index.js" & "initialList.js" into the new "reducer" folder.
So, I suppose my 2 Tab class components "HomeScreen" & "SettingsScreen" would be considered children of the parent App Component?
If so, and since they are in the same App.js file as the App Component, and since you can only use "export default" on the main App Component, I am not sure how to code the redux connect function & mapStateToProps function correctly for my HomeScreen child.
Current code for HomeScreen:
class HomeScreen extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
sharedToken: 'empty',
dataSource: []
};
}
componentDidMount() {
console.log('componentDidMount triggered...');
this.tokenRequest();
}
....
And code for calling this function:
const HomeStack = createStackNavigator({
Home: HomeScreen,
Details: DetailsScreen,
});

Ok, yes - you have two choices here:

First, you could put HomeScreen and DetailsScreen into new files, and export default them from there. Then you can import them with:

import HomeScreen from '[the path]/HomeScreen'

and use it like normal.

I would generally reccomend that choice, since it keeps the files smaller and easier to reason about; but for learning purposes, you may want to keep them all in the same file.

So: the other choice, if you keep them in the same file, is to - instead of exporting them, set them to a new variable (const) and then use that. For example, you can do:

const ConnectedHomeScreen = connect(...)(HomeScreen)

Or, something I like to do if I'm doing that, is to call my original class "UnconnectedXYZ", and the connected class I just call "XYZ"

so you would have:

class UnconnectedHomeScreen extends Component {...}

const HomeScreen = connect(...)(UnconnectedHomeScreen)

and I like to do that so that I know explicitly that the component isn't connected (I've accidentally used the wrong one too many times! :) )

Does that make sense?

Yes, making sense, thank you.
Now I have this code, but it returns another error ("You must pass a component to the function returned by connect. Instead received undefined"):
const mapStateToProps = (state, ownProps) => {
return {
items: state.initialList.items
}
}

const ConnectedHomeScreen = connect(mapStateToProps)(HomeScreen)

class HomeScreen extends Component { ... }

Do you have the line:

const ConnectedHomeScreen = connect(mapStateToProps)(HomeScreen)

above the line:

class HomeScreen extends Component { ... }

? If so, try switching those around, so that you define HomeScreen before using it in connect. Otherwise, it looks like it should work (so if that doesn't work, I'm not quite sure what's wrong)

Well, that worked like a charm!
Exciting to get past all these problems so I can continue with your tutorials.
Thank you so much for your patience and quick help on this.

And yes, to address your earlier comments, I will begin to separate these various components into separate files AFTER I can get all of this to work.
As you say, I feel it is a good learning process.

Great! Glad to help

>
You need to go PRO to post comments.

Lessons in React Native with Redux