This occurs with React + Redux Saga application my team is working on
We buy the React Isomorphic theme from Themeforest which bundles the Redux, Saga, and React Router V.4. We are now working on top of it.
I have been using React for a while but new to Redux and never experienced with such behavior. The problem is that whenever I dispatch an action, the component unmounts and remounts as the state changes
Okay, what I am doing is to fetch some user data from the API but. So this is how I come up with the following action & reducer
// Actions.js
const UserActions = {
FETCH_USER_REQUEST: 'FETCH_USER_REQUEST',
FETCH_USER_SUCCESS: 'FETCH_USER_SUCCESS',
fetch_users: () => {
return {
type: UserActions.FETCH_USER_REQUEST
}
}
}
export default UserActions;
And the reducer
// Reducer.js
export default function UserReducer(state = initialState, action) {
switch (action.type) {
case 'REQUEST_USER_SUCCESS':
return state.set('user_list', action.user_list);
default:
return state;
}
}
With Redux Saga, the middleware is created to handle async actions. This is how it looks
// Saga.js
import { all, takeEvery, call, put, fork } from 'redux-saga/effects';
import {get, post} from 'axios';
export function fetchUser() {
return get('https://mockapi.testapp.dev/users')
.then(response => {
return response.data;
}).catch(error => {
return error.data
});
}
export function* fetchUserRequest() {
yield takeEvery('FETCH_USER_REQUEST', function*() {
const resp = yield call(fetchUser);
yield put({
action: 'FETCH_USER_SUCCESS',
user_list: resp
});
});
}
export default function* rootSaga() {
yield all([
fork(fetchUserRequest)
]);
}
Now I implement the code in my component like this
// App.js
import React, {Component} from 'react';
import {connect} from 'react-redux';
import UserActions from './actions/UserAction';
const mapStateToProps = (state, ownProps) => {
return {
userList: state.User.get('user_list')
}
}
const mapDispatchToProps = dispatch => {
return {
fetchUser: () => dispatch(UserActions.fetch_users())
}
}
class App extends Component {
componentDidMount() {
this.props.fetchUser();
}
render() {
// ... The rest of the rendering processes
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
Now that you can see, with the behavior mentioned prior to this. Dispatching an action via this.props.fetchUser() cause the state to change but what I don't expect is that the component shouldn't unmount and remount because once it does so, an infinite loop occurs because the componentDidMount runs over and over and state also changes accordingly.
What I expect is to fetch the data from the API once the component mounts without remounting itself once the state changes for any reason because the theme we purchased is equipped with other base components which make use of Redux-saga to handle state and async actions. For example, the collapsable sidebar triggers a dispatch which changes the state that controls its bahavior once the users click on the it. Currently, once it does that my current component immediately unmounts unexpectedly.
Is there any possible way to solve such a problem or this is the default behavior of Redux?
componentWillMount
instead ofcomponentDidMount
. Also the component would remount if when rendering the<App>
component you added a key that is dynamic such as<App key={newestUser}
. Remounting could also occur if the parent component ofApp
only sometimes renders App. If the parent occasionally doesn't render anything then you could try giving giving App a static key like<App key="main-app" />
Changing routes remounts components, if you could share your route file maybe there's something there I could find. – Budd