I'm making my first react-native app and I cant seem to bind my actions to props. In the component this.props.actions is an empty, and LoginActions is also an empty object in the mapDispatchToProps function. This leads me to believe its an issue in the action or the connect binding. Can anyone see where I'm going wrong?
Component:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import {
View,
StyleSheet,
} from 'react-native';
import {
google,
facebook,
twitter,
} from 'react-native-simple-auth';
import LoginConstants from '../../constants/Login.constants';
import * as LoginActions from '../../actions/Login.actions';
import LoginForm from '../../components/LoginForm';
class Login extends Component {
constructor(props) {
super(props);
alert(JSON.stringify(this.props.actions))
this.loginActions = {
google,
facebook,
twitter,
};
this.loginAction = this.loginAction.bind(this);
}
loginAction(platform) {
alert(JSON.stringify(this.props.actions))
// this.loginActions[platform](LoginConstants[platform])
// .then((info) => {
// alert(info);
// // info.user - user details from the provider
// // info.credentials - tokens from the provider
// }).catch((error) => {
// throw Error(`Error ${error.code}: ${error.description}`);
// });
}
render() {
return (
<LoginForm actions={this.loginActions} loginAction={this.loginAction} />
);
}
}
Login.propTypes = {
actions: PropTypes.object.isRequired,
user: PropTypes.object
};
const styles = StyleSheet.create({
});
const mapStateToProps = (state) => {
return {
user: state.user
};
};
const mapDispatchToProps = (dispatch) => {
return {
actions: bindActionCreators(LoginActions, dispatch)
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Login);
Actions:
import LoginConstants from '../constants/Login.constants';
export function getUser(userId) {
return {
type: LoginConstants.actions.getUser,
payload: new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
userId: '123ddgs',
});
}, 2000);
});
};
};
export function saveUser(user) {
return {
type: LoginConstants.actions.saveUser,
payload: new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
userId: '123ddgs',
});
}, 2000);
})
};
};
Reducer:
import LoginConstants from '../constants/Login.constants';
const loginReducers = (state = {
user: {},
prevStates: []
}, action) => {
switch (action.type) {
case LoginConstants.actions.getUser:
state = {
...state,
user: action.payload,
prevStates: [...state.prevStates, action.payload]
};
break;
case LoginConstants.actions.saveUser:
state = {
...state,
user: action.payload,
prevStates: [...state.prevStates, action.payload]
};
break;
}
return state;
};
export default loginReducers;
Store:
import {
createStore,
combineReducers,
applyMiddleware,
} from 'redux';
import thunk from 'redux-thunk';
import promise from 'redux-promise-middleware';
import { createLogger } from 'redux-logger';
import loginReducers from './src/reducers/Login.reducers';
import beerReducers from './src/reducers/Beer.reducers';
export default createStore(
combineReducers({
loginReducers,
beerReducers,
}),
{},
applyMiddleware(createLogger(), thunk, promise())
);
JSON.stringify strips functions from its output and therefore, the actions and dispatcher were not visible in the alert output.
Related
I've got a sample website with redux(redux-saga,redux-next-wrapper).
I created all components of redux and configured them. But I got an error when dispatching in getStaticProps with title `TypeError: nextCallback is not a function. I will share my structures code and thanks to finding my problem.
Action code
import { NewsActionE } from "../../../enums/newsActionEnum"
import { FetchGetsRequest, FetchNewsSuccessPayload, FetchPostsFailure, FetchPostsFailurePayload, FetchPostsSuccess } from "../../../types/allNewsT"
export const requestNews = (): FetchGetsRequest => ({
type: NewsActionE.REQUESTNEWS
})
export const fetchNewsSuccess = (
payload: FetchNewsSuccessPayload
): FetchPostsSuccess => ({
type: NewsActionE.GETALLNEWS,
payload
});
export const ErrorNews = (
payload: FetchPostsFailurePayload
): FetchPostsFailure => ({
type: NewsActionE.Failure,
payload
});
reducers
import { HYDRATE } from "next-redux-wrapper";
import { AnyAction } from "redux";
import { NewsActionE } from "../../../enums/newsActionEnum"
export interface initialState {
pending: false
errors: null
articles: []
}
export const reducer = (state: initialState | undefined, action: AnyAction): initialState | any => {
switch (action.type) {
case HYDRATE:
// Attention! This will overwrite client state! Real apps should use proper reconciliation.
return { ...state, ...action.payload };
case NewsActionE.REQUESTNEWS:
return {
...state,
pending: true,
}
case NewsActionE.Failure:
return {
...state,
pending: false,
articles: [],
errors: action.payload.console.error
}
case NewsActionE.GETALLNEWS:
return {
...state,
pending: false,
articles: action.payload,
errors: null
}
default:
return { ...state };
}
}
sagas
import axios, { AxiosResponse } from "axios"
import http from '../../../services/httpService';
import { call, put, all, takeLatest } from 'redux-saga/effects'
import { News } from '../../../models/news/News'
import { ErrorNews, fetchNewsSuccess } from "../..";
import { NewsActionE } from "../../../enums/newsActionEnum";
const getNews = (): Promise<AxiosResponse<News, any>> =>
http.get<News>('/data/getallposts')
function* fetchNewsSaga(): any {
try {
const response = yield call(getNews);
yield put(fetchNewsSuccess({
news: response.data
}));
} catch (e) {
yield put(ErrorNews({
error: 'e.message'
}));
}
}
function* newsSaga() {
yield all([takeLatest(NewsActionE.REQUESTNEWS, fetchNewsSaga)])
}
export default newsSaga;
root saga
import { all, fork } from "#redux-saga/core/effects";
import newsSaga from "./news/newssaga";
export function* RootSaga() {
yield all([fork(newsSaga)])
}
store
import { AnyAction, applyMiddleware, createStore, Store } from "redux";
import reducers from "../reducer/news";
import createSagaMiddleware from "#redux-saga/core";
import { Task } from 'redux-saga'
import { RootSaga } from "../sagas/rootSaga";
import { Context, createWrapper } from "next-redux-wrapper";
import { initialState } from "../reducer/news/newsReducer";
import { RootState } from "..";
export interface SagaStore extends Store<initialState | any, AnyAction> {
sagaTask?: Task;
}
export const makeStore = (context: Context) => {
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
reducers,
applyMiddleware(sagaMiddleware));
(store as SagaStore).sagaTask = sagaMiddleware.run(RootSaga);
return store;
};
export const wrapper = createWrapper<Store<RootState>>(makeStore, { debug: true });
index.ts
import { END } from '#redux-saga/core'
import type { NextPage } from 'next'
import Layout from '../components/Layout'
import AllNews from '../components/news'
import { requestNews, wrapper } from '../state'
const Home: NextPage = () => {
return (
<Layout title="News site">
<p>News site Home page</p>
<AllNews />
</Layout>
)
}
export const getStaticProps = wrapper.getStaticProps(async ({ store }) => {
store.dispatch(requestNews());
// end the saga
store.dispatch(END);
await store.sagaTask.toProm();
})
export default Home
You are exporting your reducer as a named export, but import it as a default import. As a result, it will likely be undefined.
Do
import { reducer } from "../reducer/news";
instead of
import reducers from "../reducer/news";
React native app
Store(states and backend) is built with axios and redux through redux-axios middleware which requires suffixes _SUCCESS and _FAIL for the Request.
Trying to make API call with redux axios middleware. However, data is not passing to the component. Reducer is executing only Default case for some reason.
action:
import { Actions } from "../../../constants/actions";
export const getNewsBloomberg = () => {
return {
type: Actions.GET_NEWS_BLOOMBERG,
payload: {
client: "newsClient",
request: {
url: "top-headlines?sources=bloomberg",
},
},
};
};
Reducer:
import { Actions } from "../../../constants/actions";
const initialState = {
data: [],
latestUpdate: null,
loading: null,
error: false,
};
export const bloomberg = (state = initialState, action) => {
switch (action.type) {
case Actions.GET_NEWS_BLOOMBERG:
return { ...state, latestUpdate: null, loading: true, error: false };
case Actions.GET_NEWS_BLOOMBERG_SUCCESS:
const data_string = JSON.stringify(action.payload.data);
const data_parsed = JSON.parse(data_string);
const data = data_parsed.articles;
return {
...state,
latestUpdate: new Date(),
loading: false,
data: list,
};
case Actions.GET_NEWS_BLOOMBERG_FAIL:
return {
...state,
latestUpdate: null,
loading: false,
error: "No results found.",
};
default:
return { ...state };
}
};
index.js in Store:
import axios from "axios";
import { multiClientMiddleware } from "redux-axios-middleware";
import storage from "redux-persist/lib/storage";
import { createStore, applyMiddleware } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import reducers from "./reducers";
//import { API_KEY } from "react-native-dotenv";
const persistConfig = {
key: "root",
storage,
whitelist: ["favorites"],
};
const clients = {
stockClient: {
client: axios.create({
baseURL: "https://sandbox.iexapis.com",
responseType: "json",
params: {
token: "Tpk_27c",
},
}),
},
newsClient: {
client: axios.create({
baseURL: "https://newsapi.org/v2",
responseType: "json",
params: {
apiKey: "c7c",
},
}),
},
};
const persistedReducer = persistReducer(persistConfig, reducers);
const store = createStore(
persistedReducer,
// applyMiddleware(client),
applyMiddleware(multiClientMiddleware(clients))
);
const persistor = persistStore(store);
export default { store, persistor };
Reducers are combined and Provider is wrapped to the application in App.js
The component:
import React, { Component } from "react";
import { FlatList, RefreshControl } from "react-native";
import { Content, Text, View } from "native-base";
import NewsItem from "./NewsItem";
import { connect } from "react-redux";
import { getNewsBloomberg } from "../../store/actions/news";
class NewsBloomberg extends Component {
onRefresh = () => this.props.getNewsBloomberg; //merge it
refreshControl = (loading) => (
<RefreshControl
onRefresh={this.onRefresh}
refreshing={loading}
/>
);
render() {
const { data, latestUpdate, loading } = this.props.bloomberg;
return (
<View refreshControl={this.refreshControl(loading)} style={{ flex: 1 }}>
{console.log(loading)}
<FlatList
data={data}
keyExtractor={(key) => key.source.id}
renderItem={({ item, index }) => (
<NewsItem onPress={() => console.log("Pressed")} data={data} />
)}
/>
</View>
);
}
}
const mapStateToProps = (state) => {
console.log(state.bloomberg);
return { bloomberg: state.bloomberg };
};
const mapDispatchToProps = {
getNewsBloomberg,
};
export default connect(mapStateToProps, mapDispatchToProps)(NewsBloomberg);
**I noticed that reducer throws the DEFAULT case only **
Does it mean that action is not dispatching or what?
You're not calling the action creator getNewsBloomberg inside onRefresh.
onRefresh = () => this.props.getNewsBloomberg();
Your mapDispatchToProps is wrong, what mapDispatchToProps does is it gives you dispatch as a first argument by using the higher order component "connect" and by using that you can dispatch your actions in react components,
now what you are doing is you are simply calling actions and not dispatching it,
const mapDispatchToProps = (dispatch) => {
getNewsBloomberg:()=>{dispatch(getNewsBloomberg())},
};
here i am taking dispatch as first argument and invoking the action inside dispatch
I'm trying to create an alert component, however for this I need to add an item (from anywhere) to the list of alerts in the state.
I have this code:
alertReducer.js:
import { SET_ALERT, GET_ALERTS, SET_ALERT_SHOWED } from "../actions/types";
const initialState = {
alerts: [
{
id: 0,
title: "teste",
message: "teste",
isShowed: false,
type: "success"
}
]
};
export default function(state = initialState, action) {
switch (action.type) {
case SET_ALERT:
return { ...state, alert: action.payload };
case SET_ALERT_SHOWED:
return {
...state,
alert: state.alerts.map(a =>
a.id === a.payload.id ? (a = action.payload) : a
)
};
case GET_ALERTS:
return { ...state };
default:
return state;
}
}
alertActions.js
import { SET_ALERT, GET_ALERTS, SET_ALERT_SHOWED } from "./types";
import axios from "axios";
export const getAlerts = () => dispatch => {
dispatch({
type: GET_ALERTS,
payload: null
});
};
export const setAlertShowed = alert => dispatch => {
dispatch({
type: SET_ALERT_SHOWED,
payload: null
});
};
export const setAlert = alert => dispatch => {
console.log("set alert:");
this.setState(state => {
state.alert.alerts.push(alert);
return null;
});
dispatch({
type: SET_ALERT,
payload: null
});
};
alerts.js (component)
import React from "react";
import { Link } from "react-router-dom";
import { Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import {
Panel,
PanelHeader,
PanelBody
} from "./../../components/panel/panel.jsx";
import SweetAlert from "react-bootstrap-sweetalert";
import ReactNotification from "react-notifications-component";
import "react-notifications-component/dist/theme.css";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { getAlerts, setAlertShowed } from "../../actions/alertActions";
class Alerts extends React.Component {
constructor(props) {
super(props);
this.addNotification = this.addNotification.bind(this);
this.notificationDOMRef = React.createRef();
}
componentWillReceiveProps(nextProps) {
console.log("atualizou alertas");
console.log(this.props);
console.log(nextProps);
}
componentDidMount() {
this.props.getAlerts();
this.showAlerts();
}
showAlerts() {
const { alerts } = this.props;
alerts
.filter(a => !a.isShowed)
.map((a, i) => {
this.addNotification.call(this, a);
a.isShowed = true;
setAlertShowed(a);
});
}
addNotification(alert) {
this.notificationDOMRef.current.addNotification({
title: alert.title,
message: alert.message,
type: alert.type,
insert: "top",
container: "top-right",
animationIn: ["animated", "fadeIn"],
animationOut: ["animated", "fadeOut"],
dismiss: { duration: 2000 },
dismissable: { click: true }
});
}
render() {
const { alerts } = this.props;
return <ReactNotification ref={this.notificationDOMRef} />;
}
}
Alerts.propTypes = {
alerts: PropTypes.array.isRequired,
getAlerts: PropTypes.func.isRequired,
setAlertShowed: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
alerts: state.alert.alerts
});
export default connect(
mapStateToProps,
{ getAlerts, setAlertShowed }
)(Alerts);
So I have this helper I'm trying to do, it would serve so that from anywhere in the application I can trigger addAlert and generate a new alert, but I have no idea how to call the setAlert function inside the alertActions.js, what I was able to do is call the SET_ALERT through the store.dispatch, but apparently this is not triggering the setAlert or I am doing something wrong
import uuid from "uuid";
import { createStore } from "redux";
import { setAlert } from "../actions/alertActions";
import { SET_ALERT } from "../actions/types";
import alertReducer from "../reducers/alertReducer";
export function addAlert(state, title, message, type = "success") {
// const store = createStore(alertReducer);
// const state = store.getState();
const newalert = {
id: uuid.v4(),
title,
message,
isShowed: false,
type: type
};
console.log("state");
console.log(state);
// this.setState(state => {
// state.alert.alerts.push(alert);
// return null;
// });
// store.dispatch({
// type: SET_ALERT,
// payload: newalert
// });
// store.dispatch(setAlert(newalert));
// store.dispatch(SET_ALERT);
// this.setState(prevState => ({
// alert.alerts: [...prevState.alert.alerts, newalert]
// }))
}
PS. My react knowledge is very low yet and English it's not my primary language, if I don't make myself clear please ask anything.
Thank you.
Do like this:
// Create alert which you want to show
const alerts = [
{
id: 0,
title: "teste",
message: "teste",
isShowed: false,
type: "success"
}];
componentDidMount() {
this.props.getAlerts();
this.showAlerts();
// this will call alerts action
this.props.callAlert(alerts );
}
const mapDispatchToProps = dispatch=> ({
callAlert: (alert) => dispatch(setAlert(alert)),
});
export default connect(
mapStateToProps,
mapDispatchToProps,
{ getAlerts, setAlertShowed }
)(Alerts);
Finally! I created the store by adding compose and applyMiddleware, I still have to study how this works best but it worked.
The helper code to add alert looks like this:
import uuid from "uuid";
import { createStore, dispatch, compose, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { setAlert } from "../actions/alertActions";
import alertReducer from "../reducers/alertReducer";
export function addAlert(title, message, type = "success") {
const store = createStore(alertReducer, compose(applyMiddleware(thunk)));
const newalert = {
id: uuid.v4(),
title,
message,
isShowed: false,
type: type
};
store.dispatch(setAlert(newalert));
}
I have a component that should navigate when a user is authenticated:
componentDidUpdate(prevProps, prevState) {
if (this.props.authenticated) {
this.props.navigation.navigate('Main')
}
}
When I dispatch authLogin it should cause a rerender, which handles the navigation:
export const authLogin = (username, password) => {
return dispatch => {
dispatch(authStart());
axios.post(`http://10.0.2.2:8000/api/v1/rest-auth/login/`, {
username: username,
password: password
})
.then(response => {
var token = response.data.key;
try {
AsyncStorage.setItem('token', token);
} catch (err) {
console.log(err)
}
dispatch(authSuccess(token));
})
.catch(err => {
dispatch(authFail());
console.log(err);
})
}
}
Here is my reducer:
export default function (state = initialState, action) {
switch (action.type) {
case "AUTH_START": {
return {
...state,
authenticating: true,
}
}
case "AUTH_SUCCESS": {
return {
...state,
authenticating: false,
authenticated: true,
token: action.token,
}
}
case "AUTH_FAIL": {
return {
...state,
authenticating: false,
authenticated: false,
}
}
case "AUTH_LOGOUT": {
return {
...state,
authenticating: false,
authenticated: false,
token: null,
}
}
default:
return state
}
}
and action creators:
export const authStart = () => ({type: "AUTH_START"})
export const authSuccess = token => ({type: "AUTH_SUCCESS", token})
export const authFail = () => ({type: "AUTH_FAIL"})
My console is logging that Redux actions are dispatched and that the state is changing, but no rerendering is happening. Here's the whole component:
import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import LoginForm from '../components/LoginForm';
import { authLogin } from '../actions/authActions';
export class LoginScreen extends Component {
handlePress = async (username, password) => {
await this.props.authLogin(username, password);
}
componentDidUpdate(prevProps, prevState) {
if (this.props.authenticated) {
this.props.navigation.navigate('Main')
}
}
render() {
return (
<View style={styles.loginForm}>
<LoginForm handlePress={this.handlePress} {...this.props} />
</View>
);
}
}
const mapState = state => {
return {
authenticated: state.auth.authenticated
}
};
const mapDispatch = dispatch => {
return bindActionCreators({
authLogin,
}, dispatch)
};
export default connect(mapState, mapDispatch)(LoginScreen);
LoginScreen.propTypes = {
authLogin: PropTypes.func.isRequired,
authenticated: PropTypes.bool.isRequired,
};
const styles = StyleSheet.create({
loginForm: {
justifyContent: 'center',
alignItems: 'center',
flex: 1
}
});
and here's my store:
import { combineReducers } from 'redux';
import { createStore, applyMiddleware } from 'redux';
import { logger } from 'redux-logger';
import thunk from 'redux-thunk';
import auth from './auth'
const reducer = combineReducers({auth})
const enhancer = applyMiddleware(thunk, logger)
const store = createStore(reducer, enhancer)
export default store
The store is connected in the Provider in App.js.
I added another reducer, which fixed it instantly. Apparently redux didn't like that combineReducers() only had one argument.
i.e. change
const reducer = combineReducers({auth})
to
const reducer = combineReducers({auth, otherReducer})
Why not put the authentication check and navigation statement inside the handlePress().
handlePress = async (username, password) => {
await this.props.authLogin(username, password);
if (this.props.authenticated) {
this.props.navigation.navigate('Main')
}
}
After the authLogin() dispatches the action and state is updated, you can check the authentication status and navigate the user.
Hope this helps!
I am fetching an api with axios and the action is being fired after the "persist/REHYDRATE" action resulting in the following
"redux-persist/autoRehydrate: 1 actions were fired before rehydration completed...."
If I delete a tweet one by one and then refresh my browser, it does not store the state. Can't seem to crack this..
Client.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from "react-redux"
import { compose, applyMiddleware, createStore } from 'redux';
import logger from "redux-logger"
import thunk from "redux-thunk"
import promise from "redux-promise-middleware"
import {persistStore, autoRehydrate} from 'redux-persist'
import tweetApp from "./reducers"
import Layout from "./components/Layout"
import { REHYDRATE } from 'redux-persist/constants'
import createActionBuffer from 'redux-action-buffer'
//const middleware = applyMiddleware(promise(), thunk, logger())
let enhancer = compose(
autoRehydrate({ log: true }),
applyMiddleware(
promise(), thunk, logger(), createActionBuffer(REHYDRATE)
)
)
const store = createStore(
tweetApp,
enhancer
);
const persistConfig = {
whitelist : ["tweets"]
};
persistStore(store, persistConfig);
render(
<Provider store={store}>
<Layout />
</Provider>,
document.getElementById('app')
);
tweetsReducer.js
import {REHYDRATE} from 'redux-persist/constants'
export default function reducer(state={
tweets: [],
fetching: false,
fetched: false,
error: null,
}, action) {
switch (action.type) {
case "persist/REHYDRATE": {
const incoming = action.payload.tweets; // Carts is the name of the reducer
if (incoming) return {...state, ...incoming}
}
case "FETCH_TWEETS": {
return {...state, fetching: true}
}
case "FETCH_TWEETS_REJECTED": {
return {...state, fetching: false, error: action.payload}
}
case "FETCH_TWEETS_FULFILLED": {
return {
...state,
fetching: false,
fetched: true,
tweets: action.payload,
}
}
case "ADD_TWEET": {
return {
...state,
tweets: [...state.tweets, action.payload],
}
}
case "UPDATE_TWEET": {
const { id, text } = action.payload
const newTweets = [...state.tweets]
const tweetToUpdate = newTweets.findIndex(tweet => tweet.id === id)
newTweets[tweetToUpdate] = action.payload;
return {
...state,
tweets: newTweets,
}
}
case "DELETE_TWEET": {
return {
tweets: [
...state.tweets.slice(0, action.payload),
...state.tweets.slice(action.payload + 1)
],
}
}
}
return state
}
tweetsActions.js
import axios from "axios";
export function fetchTweets() {
return function(dispatch) {
axios.get("http://rest.learncode.academy/api/test123/tweets")
.then((response) => {
dispatch({type: "FETCH_TWEETS_FULFILLED", payload: response.data})
})
.catch((err) => {
dispatch({type: "FETCH_TWEETS_REJECTED", payload: err})
})
}
}
export function addTweet(id, text) {
return {
type: 'ADD_TWEET',
payload: {
id,
text,
},
}
}
export function updateTweet(id, text) {
return {
type: 'UPDATE_TWEET',
payload: {
id,
text,
},
}
}
export function deleteTweet(id) {
return { type: 'DELETE_TWEET', payload: id}
}
layouts.js
import React from "react"
import { connect } from "react-redux"
import { fetchUser } from "../actions/userActions"
import { fetchTweets } from "../actions/tweetsActions"
import { deleteTweet } from "../actions/tweetsActions"
#connect((store) => {
return {
user: store.user.user,
userFetched: store.user.fetched,
tweets: store.tweets.tweets,
};
})
export default class Layout extends React.Component {
componentWillMount() {
this.props.dispatch(fetchUser())
this.props.dispatch(fetchTweets())
}
fetchTweets() {
//this.props.dispatch(fetchTweets())
}
deleteTweet(idx, e) {
this.props.dispatch(deleteTweet(idx))
}
render() {
const { user, tweets, i } = this.props;
//console.log(this.props)
const mappedTweets = tweets.map((tweet, i) => <li key={i}>{tweet.text}<button onClick={this.deleteTweet.bind(this, i)}>delete</button></li>)
return <div>
<h1>{user.name}</h1>
<ul>{mappedTweets}</ul>
</div>
}
}
UPDATE AND SAME ISSUE:
I tried replacing "componentWILLMount() with componentDidMount()" and the issue still occurs. See logged output:
Move your fetchTweets and fetchUser calls to componentDidMount, otherwise all your code is executed synchronously: from the store being created to your Layout being instantiated and rendered.
componentWillMount is called before render, while componentDidMount is called after the component has been rendered for the first time.