malcoauri
malcoauri

Reputation: 12189

Redirect after success async action with createAsyncThunk

There is the following component code:

import React from 'react';

import { useSelector, useDispatch } from 'react-redux';

import { RootStateType, AppDispatch} from '../../store';

import { changeTask } from '../../reducers/todo'; 

import { addTodo } from '../../async-thunks/todo';

import Form from '../../components/form';
import Button from '../../components/button';
import Input from '../../components/input';

const NewTask: React.FC = () => {
  const dispatch = useDispatch<AppDispatch>();

  const newTask = useSelector((state: RootStateType) => state.todo.newTask);

  const onTaskAdd = async (event: React.FormEvent<HTMLFormElement>) => {
    const res = await dispatch(addTodo(newTask));
  };

  const onTaskNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    event.stopPropagation();

    dispatch(changeTask(event.target.value));
  };

  return (
    <Form onSubmit={onTaskAdd}>
      <Input type="text" value={newTask} onChange={onTaskNameChange}></Input>
      <Button type="submit">Submit</Button>
    </Form>
  );
};

export default React.memo(NewTask);

Also there is a simple async thunk:

export const addTodo = createAsyncThunk('tasks/addTask', async(name: string): Promise<string> => {
  const response = await fetch('/api/tasks', { method: 'POST', body: JSON.stringify({ name }) });
    
  return await response.json();
});

As you could see I've just created a simple async thunk, and I'd like to redirect to '/tasks' route from my component after success API request. I want to do it in my component, not async thunk. How should I do it correctly? Problem is to do it after success request; if error, I don't want to do redirect.

Upvotes: 3

Views: 2775

Answers (2)

markerikson
markerikson

Reputation: 67459

The typical approach would be to await the promise returned by the thunk, and then unwrap it to determine success/failure. From there you can do a history.push().

Note that the upcoming Redux Toolkit 1.6 release will have a .unwrap() method on the returned promise to make it a bit similar:

// now
const resultAction = await dispatch(someAsyncThunk());
try {
  unwrapResult(resultAction);
  // must be okay
  history.push('/some/route');
} catch (err) {
  // must have failed
}

// Upcoming RTK 1.6
try {
  await dispatch(someAsyncThunk()).unwrap()
  history.push('/some/route');
} catch (err) {}

Upvotes: 1

Shambala
Shambala

Reputation: 104

You can dispatch some "flag" to store from your thunk upon successful request.

Then in your component using useSelector you should get access to that "flag" from your store.

In useEffect you can use history.push('/tasks') with condition. so it would looks like this:

useEffect(() => {

if(flag) {
 history.push('/tasks')
 }
}, [flag])

Upvotes: 0

Related Questions