I've create a wizard form that I change a little bit. Each step of the form fetch some data from API when componentWillMount and when user click on "next" to go to the next form part, I call dispatch another action with componentWillUnmout to dispatch an Update (PUT) action from the API.
I'm using redux-saga with react.
Here is the saga.js file :
import { call, put, takeEvery } from 'redux-saga/effects';
import accountApi from '../../api/account';
import * as actions from '../../actions';
import {
FETCH_ACCOUNT_REQUEST,
FETCH_ACCOUNT_SUCCESS,
UPDATE_ACCOUNT_REQUEST,
UPDATE_ACCOUNT_SUCCESS
} from '../../actions/types';
export function* fetchAccount(action) {
const account = yield call(accountApi.fetchAccount, action.params);
yield put({ type: FETCH_ACCOUNT_SUCCESS, account: account });
}
export function* updateAccount(action) {
const accountUpdated = yield call(accountApi.updateAccount, action.params, action.accountUpdated);
yield put({ type: UPDATE_ACCOUNT_SUCCESS, accountUpdated: accountUpdated });
}
export function* accountListener() {
yield takeEvery(FETCH_ACCOUNT_REQUEST, fetchAccount);
yield takeEvery(UPDATE_ACCOUNT_REQUEST, updateAccount);
}
There is the API file :
import axios from 'axios';
const baseUrl = '<link>';
const accountApi = {
fetchAccount(params) {
return axios.get(`${baseUrl}${params}`)
.then(response => {
return response.data
})
},
updateAccount(params, accountUpdated) {
return axios.put(`${baseUrl}${params}`, accountUpdated)
.then(response => {
return response.data
})
}
}
export default accountApi;
the action :
import axios from 'axios';
import {
FETCH_ACCOUNT_REQUEST,
UPDATE_ACCOUNT_REQUEST
} from './types';
export function fetchAccount(params) {
return {
type: FETCH_ACCOUNT_REQUEST,
params
}
}
export function updateAccount(params, accountUpdated) {
return {
type: UPDATE_ACCOUNT_REQUEST,
params,
accountUpdated
}
}
the reducer :
import {
FETCH_ACCOUNT_REQUEST,
FETCH_ACCOUNT_SUCCESS,
UPDATE_ACCOUNT_REQUEST,
UPDATE_ACCOUNT_SUCCESS
} from '../actions/types';
export default function(state = null, action) {
switch (action.type) {
case FETCH_ACCOUNT_REQUEST:
return null;
case FETCH_ACCOUNT_SUCCESS:
return action.account;
case UPDATE_ACCOUNT_REQUEST:
return null;
case UPDATE_ACCOUNT_SUCCESS:
return action.accountUpdated;
default:
return state;
}
}
And the component :
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Field, reduxForm } from 'redux-form';
import * as actions from '../../actions';
import validate from './validate';
class FormGlobalInformations extends Component {
componentWillMount() {
const fakeAccountId = '?accountId=0012400000oAMhY';
this.props.actions.fetchAccount(fakeAccountId);
}
componentDidMount() {
if (this.props.account) {
this.props.initialize({
companyName: this.props.account.companyName,
typologie: this.props.account.typologie,
phone: this.props.account.phone
});
}
}
componentWillUnmount() {
const fakeAccountId = '?accountId=0012400000oAMhY';
this.props.actions.updateAccount(fakeAccountId, this.props.form.Information.values);
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<Field
label="Nom de l'établissement"
name="companyName"
type="text"
className="form-group"
component={this.renderFields}
/>
<Field
label="Type d'établissement : "
name="typologie"
component={this.renderSelect}
className="form-group"
/>
<Field
label="Votre numéro de téléphone de contact"
name="phone"
type="number"
className="form-group"
component={this.renderFields}
/>
<button type="submit" className="btn btn-tiller-full btn-tiller-right">Suite</button>
</form>
);
}
}
function mapStateToProps(state) {
return {
account: state.account,
form: state.form
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actions, dispatch)
}
}
FormGlobalInformations = connect(mapStateToProps, mapDispatchToProps)(FormGlobalInformations);
FormGlobalInformations = reduxForm({
form: 'Information',
destroyOnUnmount: false,
validate
})(FormGlobalInformations);
export default FormGlobalInformations;
(The next form step component is the same so I fetch data onmount and I update on unmount).
Here is the index.js file :
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
// import ReduxThunk from 'redux-thunk';
import { all } from 'redux-saga/effects';
import createSagaMiddleware from 'redux-saga';
import reducers from './reducers';
// Components
import Informations from './components/Informations/Informations';
import Navigation from './components/Navigation/Navigation';
import Header from './components/Navigation/Header';
import { accountListener } from './services/account/saga';
function* RootListener() {
yield all([
accountListener()
]);
}
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
reducers,
applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(RootListener);
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<div>
<Header />
<Navigation />
<Switch>
<Route path="/informations" component={Informations} />
</Switch>
</div>
</BrowserRouter>
</Provider>,
document.querySelector('.container-fluid')
);
Here is the error that I have when I try to update :
And I have a OPTIONS request...
Someone could help ?