How to work with API call action in redux?

不羁岁月 提交于 2021-01-29 03:23:37

问题


I am new to redux and I am trying to make it work with my application, but I have problems with understanding how to work with async actions in it. I have action that is api call. This action should be called as soon as my other state is not empty. I do not get any mistakes but do not think that my action is called since the data is empty. Can anybody help to understand what I am doing wrong?

Here is my actions.js. The wordsFetchData is the action I need to call:

 export function wordsFetchDataSuccess(items){
    return{
        type: 'WORDS_FETCH_DATA_SUCCESS',
        items
    };
 }

 export function wordsAreFetching(bool){
     return{
        type: 'WORDS_ARE_FETCHING',
        areFetching: bool
     }
 }

 export function wordsHasErrored(bool) {
     return {
        type: 'WORDS_HAS_ERRORED',
        hasErrored: bool
     };
 }

 export function wordsFetchData(parsed) {
    return (dispatch) => {
        dispatch(wordsAreFetching(true));

        fetch('URL', {
            method: "POST",
            headers: {
                "Content-type": "application/json"
            },body: JSON.stringify({
                 words: parsed
        })
    })
        .then((response) => {
            if (!response.ok) {
                throw Error(response.statusText);
            }

            dispatch(wordsAreFetching(false));

            return response;
        })
        .then((response) => response.json())
        .then((items) => dispatch(wordsFetchDataSuccess(items)))
        .catch(() => dispatch(wordsHasErrored(true)));
    };
 }

Here are my reducers:

export function word(state = [], action) {
switch (action.type) {
    case 'WORDS_FETCH_DATA_SUCCESS':
        return action.items;

    default:
        return state;
    }
}

export function wordsAreFetching(state = false, action) {
    switch (action.type) {
        case 'WORDS_ARE_FETCHING':
            return action.areFetching;

        default:
            return state;
    }
}

export function wordsFetchHasErrored(state = false, action) {
    switch (action.type) {
        case 'WORDS_HAS_ERRORED':
           return action.hasErrored;

    default:
        return state;

    }

 }

This is my componentDidMount function:

componentDidMount = (state) => {
    this.props.fetchData(state);
};

This is the function after terminating which the action should be called:

 parseInput = async () => {
    console.log(this.state.textInput);
    let tempArray = this.state.textInput.split(" "); // `convert 
    string into array`
    let newArray = tempArray.filter(word => word.endsWith("*"));
    let filterArray  = newArray.map(word => word.replace('*', ''));
    await this.setState({filterArray: filterArray});
    await this.props.updateData(this.state.filterArray);
    if (this.state.projectID === "" && this.state.entity === "")
        this.dialog.current.handleClickOpen();
    else
        if (this.state.filterArray.length !== 0)
            this.componentDidMount(this.state.filterArray);
    };

These are the mapStateToProps and mapDispatchToProps functions.

const mapStateToProps = (state) => {
    return {
        items: state.items,
        hasErrored: state.wordsFetchHasErrored,
        areFetching: state.wordsAreFetching
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        fetchData: wordsFetchData
    };
};

回答1:


You only need one action for executing fetching (i.e WORDS_ARE_FETCHING), the rest of the cases (i.e WORDS_HAS_ERRORED & WORDS_FETCH_DATA_SUCCESS) can be handled inside your reducer.

Your action:

 export function wordsAreFetching(){
     return{
        type: 'WORDS_ARE_FETCHING',
     }
 }

Your new reducer:

export function word(state = [], action) {
switch (action.type) {
    case 'WORDS_ARE_FETCHING':
        return {...state, error: false, areFetching: true};
    case 'WORDS_FETCH_DATA_SUCCESS':
        return {...state, items: action.payload , areFetching: false};
    case 'WORDS_HAS_ERRORED':
        return {...state, error: true, areFetching: false};
    default:
        return state;
}

Then you can trigger WORDS_FETCH_DATA_SUCCESS after you get the data from here:

export function wordsFetchData() {
    try {
        const response = await axios.get(YOUR_URL);
        return dispatch({ type: WORDS_FETCH_DATA_SUCCESS, payload: response.data });
    } catch (err) {
        return dispatch({ type: WORDS_HAS_ERRORED });
    }
 }

Take a look at this example, it uses axios that can help you with async calls.




回答2:


A couple of things:

  1. No need to pass state into your componentDidMount, your mapDispatchToProps is not using it.

  2. Here is a suggestion to structure those functions. They are a bit more concise and readable.

const mapStateToProps = ({items, wordsAreFetching, wordsFetchHasError}) => ({
   items,
   hasErrored: wordsFetchHasErrored,
   areFetching: wordsAreFetching,
});

const mapDispatchToProps = () => ({
   fetchData: wordsFetchData(),
});

Other notes and helpful things: If you're using thunk, you'll have access to your entire redux store in here as a second argument. For example:

    return (dispatch, getState) => {
        dispatch(wordsAreFetching(true));
        console.log('getState', getState());
       const { words } = getState().items;
// This is a great place to do some checks to see if you _need_ to fetch any data!
// Maybe you already have it in your state?

     if (!words.length) {
        fetch('URL', {
            method: "POST",
            headers: {
                ......
      }

    })

I hope this helps, if you need anything else feel free to ask.



来源:https://stackoverflow.com/questions/56126566/how-to-work-with-api-call-action-in-redux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!