'How can i redirect after successful submit of form using react-redux
action.js
import axios from 'axios';
import { EVENT_ADD_FAIL, EVENT_ADD_REQUEST, EVENT_ADD_SUCCESS } from '../constraints/eventConstraint';
const addEvent = (event) => async (dispatch) => {
dispatch({ type: EVENT_ADD_REQUEST, payload: event });
try {
const { data } = await axios.post(`http://localhost:4000/event`, event);
dispatch({ type: EVENT_ADD_SUCCESS, payload:data });
}
catch (error) {
dispatch({ type: EVENT_ADD_FAIL, payload:error.message });
};
};
export { addEvent };
constraint.js
export const EVENT_ADD_REQUEST = 'EVENT_ADD_REQUEST';
export const EVENT_ADD_SUCCESS = 'EVENT_ADD_SUCCESS';
export const EVENT_ADD_FAIL = 'EVENT_ADD_FAIL';
reducer.js
import {EVENT_ADD_FAIL, EVENT_ADD_REQUEST, EVENT_ADD_SUCCESS } from "../constraints/eventConstraint";
function eventAddReducer(state = {}, action) {
switch(action.type) {
case EVENT_ADD_REQUEST:
return { loading: true };
case EVENT_ADD_SUCCESS:
return { loading: false, event: action.payload, success:true };
case EVENT_ADD_FAIL:
return { loading: false, error: action.payload, success:false };
default:
return state
};
};
export { eventAddReducer }
store.js
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { eventAddReducer } from './reducers/eventReducer';
const initialState = {};
const reducer = combineReducers({
addEvent: eventAddReducer
});
const store = createStore(reducer, initialState, compose(applyMiddleware(thunk)));
export default store
event.js
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useHistory } from 'react-router-dom';
import { addEvent } from '../actions/eventAction';
const AddEvent = () => {
const history = useHistory();
const [event, setEvent] = useState();
const addNewEvent = useSelector(state => state.addEvent);
console.log(addNewEvent)
const dispatch = useDispatch();
const handleChange = e => {
setEvent({ ...event,[e.target.name]:e.target.value})
};
const submitHandler = async (e) => {
e.preventDefault();
await dispatch(addEvent(event));
};
// if(addNewEvent.success === true) {
// history.push('/')
// }; ===========>>>>>>>>>>> It works at first but after submission first time next time it automatically redirects to '/' because react-redux holds state
return (
<>
<form onSubmit = { submitHandler } >
<div className="form-group">
<label htmlFor="name">Name:</label>
<input type="text" className="form-control" id="name" name="name" onChange={e => handleChange(e)} />
</div>
<div className="form-group">
<label htmlFor="description">Description:</label>
<input type="text" className="form-control" id="description" name="description" onChange={e => handleChange(e)} />
</div>
<div className="form-group">
<label htmlFor="price">Price:</label>
<input type="text" className="form-control" id="price" name="price" onChange={e => handleChange(e)} />
</div>
<Link to='/'> <button type="button" className="btn btn-success"> Back </button> </Link>
<button type="submit" className="btn btn-success float-right"> Add Event </button>
</form>
</>
)
};
export default AddEvent
Everything is working fine but I want after successful submission of the form it needs to redirect to some page. It is simple without react-redux we can simply redirect after submission of form but I am trying to learn redux and don't know much about redux. I tried to use success = true in reducer it works at the first time but as redux holds state when I tried to open the link it automatically redirects to the homepage as success = true is hold by react-redux. Any help will be appreciated
Solution 1:[1]
I ran into the same problem now, and I solved it in two ways
- The first: to complete your solution at
event.js
file:
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useHistory } from 'react-router-dom';
import { addEvent } from '../actions/eventAction';
const AddEvent = () => {
const history = useHistory();
const [event, setEvent] = useState();
const addNewEvent = useSelector(state => state.addEvent);
console.log(addNewEvent)
const dispatch = useDispatch();
const handleChange = e => {
setEvent({ ...event,[e.target.name]:e.target.value})
};
const submitHandler = async (e) => {
e.preventDefault();
await dispatch(addEvent(event));
};
addNewEvent.success && history.push('/')
return (
<>
// after submition success only you will redirect to "/"
{addNewEvent.success && history.push('/')}
<form onSubmit = { submitHandler } >
<div className="form-group">
<label htmlFor="name">Name:</label>
<input type="text" className="form-control" id="name" name="name" onChange={e => handleChange(e)} />
</div>
<div className="form-group">
<label htmlFor="description">Description:</label>
<input type="text" className="form-control" id="description" name="description" onChange={e => handleChange(e)} />
</div>
<div className="form-group">
<label htmlFor="price">Price:</label>
<input type="text" className="form-control" id="price" name="price" onChange={e => handleChange(e)} />
</div>
<Link to='/'> <button type="button" className="btn btn-success"> Back </button> </Link>
<button type="submit" className="btn btn-success float-right"> Add Event </button>
</form>
</>
)
};
export default AddEvent
we can only access success value from store reducer after return not before, so you can access value every re-render and redirect based on your condition
now in react-router-dom v6
you can use useNavigate()
and make changes for below lines
import { Link, useNavigate } from "react-router-dom";
// rest of imports
const AddEvent = () => {
const navigate = useNavigate();
//rest of code
return (
<>
{addNewEvent.success && navigate('/')}
//rest of code
</>
)
};
export default AddEvent
- The second: you can make condition at
action.js
by sending navigate as an argument on dispatch action and write your condition after dispatch success as below
event.js
file
import { Link, useNavigate } from "react-router-dom";
// rest of imports
const AddEvent = () => {
const navigate = useNavigate();
const submitHandler = async (e) => {
e.preventDefault();
await dispatch(addEvent(event,navigate));
};
//rest of code
return (
<>
//rest of code
</>
)
};
export default AddEvent
and at action.js
file
import axios from 'axios';
import { EVENT_ADD_FAIL, EVENT_ADD_REQUEST, EVENT_ADD_SUCCESS } from '../constraints/eventConstraint';
const addEvent = (event,navigate) => async (dispatch) => {
dispatch({ type: EVENT_ADD_REQUEST, payload: event });
try {
const { data } = await axios.post(`http://localhost:4000/event`, event);
dispatch({ type: EVENT_ADD_SUCCESS, payload:data });
//add your navigation or condition here
navigate("/");
}
catch (error) {
dispatch({ type: EVENT_ADD_FAIL, payload:error.message });
};
};
export { addEvent };
Solution 2:[2]
First: Make sure you reset success
per action:
function eventAddReducer(state = {}, action) {
switch(action.type) {
case EVENT_ADD_REQUEST:
return {
loading: true,
success: null // <-- Look at this
};
/** ... */
};
};
Second: Connect success
store-variable to your component, and check for it in componentDidupdate
event like:
import { connect } from 'react-redux';
class AddEvent extends React.Component {
componentDidUpdate(prevProps) {
const {success} = this.props;
const {succcess: prevSuccess} = prevProps;
if (success && success !== prevSuccess) {
/** Redirect here */
}
}
/** .... */
}
const mapStateToProps = ({ addEvent: { success } }) => ({
success
});
export default connect(mapStateToProps)(AddEvent);
Using Hooks
const AddEvent = ({ success }) => {
useEffect(() => {
if (success) {
/** Redirect here */
}
}, [success]); // <-- This will make sure that the effect only runs when success variable has changed
};
const mapStateToProps = ({ addEvent: { success } }) => ({
success
});
export default connect(mapStateToProps)(AddEvent);
Solution 3:[3]
I know this not the most ideal solution , but how about creating an action that will reset success and dispatch it inside of an useEffect?
Something like this:
Reducer
import {EVENT_ADD_FAIL, EVENT_ADD_REQUEST, EVENT_ADD_SUCCESS } from "../constraints/eventConstraint";
function eventAddReducer(state = {}, action) {
switch(action.type) {
case EVENT_ADD_REQUEST:
return { loading: true };
case EVENT_ADD_SUCCESS:
return { loading: false, event: action.payload, success:true };
case EVENT_ADD_FAIL:
return { loading: false, error: action.payload, success:false };
case RESET:
return {
...state,
loading: false,
success:false
} // This will reset everything including success
default:
return state
};
};
export { eventAddReducer }
and in your event.js file call an action that will dispatch RESET. Make sure you put it inside of an useeffect.
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useHistory } from 'react-router-dom';
import { addEvent } from '../actions/eventAction';
const AddEvent = () => {
const history = useHistory();
const [event, setEvent] = useState();
const addNewEvent = useSelector(state => state.addEvent);
console.log(addNewEvent)
const dispatch = useDispatch();
React.useEffect(() =>{
myResetAction()
}, [])
const handleChange = e => {
setEvent({ ...event,[e.target.name]:e.target.value})
};
const submitHandler = async (e) => {
e.preventDefault();
await dispatch(addEvent(event));
};
// if(addNewEvent.success === true) {
// history.push('/')
// }; ===========>>>>>>>>>>> It works at first but after submission first time next time it automatically redirects to '/' because react-redux holds state
return (
<>
<form onSubmit = { submitHandler } >
<div className="form-group">
<label htmlFor="name">Name:</label>
<input type="text" className="form-control" id="name" name="name" onChange={e => handleChange(e)} />
</div>
<div className="form-group">
<label htmlFor="description">Description:</label>
<input type="text" className="form-control" id="description" name="description" onChange={e => handleChange(e)} />
</div>
<div className="form-group">
<label htmlFor="price">Price:</label>
<input type="text" className="form-control" id="price" name="price" onChange={e => handleChange(e)} />
</div>
<Link to='/'> <button type="button" className="btn btn-success"> Back </button> </Link>
<button type="submit" className="btn btn-success float-right"> Add Event </button>
</form>
</>
)
)}
Doing this will help.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Osama Mohamed Ammar |
Solution 2 | |
Solution 3 | Suraj Auwal |