Axios call in useReducer returning promise and not data

2.6k Views Asked by At

I am using useReducer in my context provider. The idea is that I will be a central place for my state and dispatch functions to live.

I am making an axios call to a datapase to fetch projects. However, when I return in the dispatch function, it is returning a promise. How can I return the data from the axios call so that it stores the data from the call in state?

const initState = []

const projectsReducer = async (state, action) => {
    switch(action.type) {
        case 'FETCH_PROJECTS':
            const req = await axios.get('/api/fetch_projects')
            const { data } = req
            return {...state, data}
            
        default: 
            return state

    }
}

useEffect(() => {
    const initFetch = () => {
        projectsDispatch({type: 'FETCH_PROJECTS'})
    }
    initFetch()
}, [])


const [projects, projectsDispatch] = useReducer(projectsReducer, initState)
1

There are 1 best solutions below

0
On BEST ANSWER

Do your fetch within the effect, then pass the data into the reducer.

A reducer is a pure function that should do no side effects. Plus whatever data is returned from the reducer is set as the next state. So, an async function always returns a promise - which means that you are setting the state of projects to be a promise for the data.

If you refactor your code as follows, it should work.

const initState = {data: []};

const projectsReducer = (state, action) => {
    switch(action.type) {
        case 'FETCH_PROJECTS':
            const { data } = action.payload;
            return {...state, data}
            
        default: 
            return state

    }
}
const [projects, projectsDispatch] = useReducer(projectsReducer, initState)

useEffect(() => {
    const initFetch = async () => {
        const req = await axios.get('/api/fetch_projects')
        projectsDispatch({type: 'FETCH_PROJECTS', payload: {data: req.data}})
    }
    initFetch()
}, [])
// data is in projects.data;

Though since it's more simple, you don't really need a reducer:

const [projects, setProjects] = useState([]);

useEffect(() => {
    const initFetch = async () => {
        const req = await axios.get('/api/fetch_projects')
        setProjects(req.data);
    }
    initFetch()
}, [])
// data is in projects