This is a bit of a lengthy one to explain. As briefly as possible: I have two components, Employees and AddEmployee - these are both attached to the routes /employees and employees/add respectively. A link from the Employee component will push employees/add to BrowserHistory, and vice versa (the AddEmployee component will also push /employees if the form is successfully submitted, or if the user clicks 'cancel').
If I navigate to /employees, the component works fine. If I click to navigate to /employees/add, that component works fine. If I click 'cancel' or submit the form to redirect back to /employees... the component breaks.
Through much debugging I've determined that this is because redux state for AddEmployee is persisting through to Employee. My guess would be this is because they both make use of the same saga. I've written a single get Redux saga to handle requests to the remote API. Employees obviously uses the get saga to retrieve all users, while AddEmployee uses the get saga to retrieve possible locations to assign the user to.
When Employees is loaded, the state of the apiGet saga contains the retrieved employees. When AddEmployee is loaded, the state of the apiGet saga contains the retrieved locations. When you then navigate back to Employees, the state of the apiGet saga still contains the retrieved locations and it does not run again to load the employees again.
How can I solve this?
I've done my best to condense the code below to the relevant portions.
The get Saga:
function getApi(endpoint, token) {
return fetch(apiUrl + endpoint, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
}
}).then(handleApiErrors)
.then(response => response.json())
.catch((error) => {throw error})
}
function* apiGetFlow(endpoint) {
let response, token
try {
token = localStorage.getItem('token')
token = JSON.parse(token)
response = yield call(getApi, endpoint, token)
yield put({ type: CLIENT_GET_SUCCESS, response: response })
} catch(error) {
...
}
return response
}
function* apiGetWatcher() {
while(true) {
const { endpoint } = yield take(CLIENT_GET_REQUESTING)
const task = yield fork(apiGetFlow, endpoint)
}
}
export default apiGetWatcher
The Employees component:
class Employees extends Component {
componentDidMount() {
this.usersGet()
}
usersGet() {
this.props.apiGetRequest('users')
}
render() {
...
}
}
const mapStateToProps = state => {
return {
users: state.apiGet,
}
}
const connected = connect(mapStateToProps, { apiGetRequest })(Employees)
export default connected
The AddEmployee component:
class AddEmployeeForm extends Component {
componentDidMount() {
this.locationsGet()
}
locationsGet() {
this.props.apiGetRequest('locations')
}
render() {
...
}
}
const mapStateToProps = state => {
return {
locations: state.apiGet,
save: state.apiPost,
}
}
const formed = reduxForm({
form: 'addemployee',
})(AddEmployeeForm)
const connected = connect(mapStateToProps, { apiGetRequest, apiPostRequest })(formed)
export default connected