Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger an action on event with react-redux

I am using react / redux / react-redux to implement a modal form that do an ajax request.

If I am correct, react-redux enable you to :

  • displays data from the redux store to your componant
  • dispatch an event from the container to redux

I am also using redux-saga to handle Ajax request triggered by redux.

However, I have no idea how to trigger an action (ex: close the modal form) when a specific event is triggered from Redux.

Example of code :

class MyFormDialog extends React.Component {
    state = {
        open: false,
    };


    handleOpen = () => {
        this.setState({open: true});
    };

    handleClose = () => {
        this.setState({open: false});
    };

    render() {
        const actions = [
            <FlatButton
                label="Cancel"
                onTouchTap={this.handleClose}
            />,
            <FlatButton
                label="Submit"
                onTouchTap={this.props.ajaxRequest}
            />,
        ];

        return (
            <div>
                <MenuItem primaryText="Make a request"  onTouchTap={this.handleOpen}/>
                <Dialog
                    title="Make a request"
                    actions={actions}
                    modal={true}
                    open={this.state.open}
                    onRequestClose={this.handleClose} />
            </div>
        );
    }
}

const mapStateToProps = (state, ownProps) => {
    return {
        loading: state.isLoading,
        success: state.success,
        error: state.error,
    }
};

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        ajaxRequest: (url, tags) => {
            dispatch({type: "AJAX_REQUESTED"})
        },
    }
};

const ConnectedMyFormDialog = connect(
    mapStateToProps,
    mapDispatchToProps
)(MyFormDialog );

export default ConnectedMyFormDialog ;

Reducers are built as the following:

  • isLoading = true when AJAX_REQUESTED is sent (others are set to false)
  • success = true when AJAX_SUCCESS is sent (others are set to false)
  • error = true when AJAX_FAIL is sent (others are set to false)

So I would like to change state.open to false when isLoading change from true to false AND success change to false to true.

I have no idea how to do that without messing with state.

Edit:

Here is my sagas code, to handle events:

function* handleAjaxRequest(action) {
    try {
        yield call(api.doRequest);
        yield put({type: "AJAX_SUCCESS"});
    } catch (e) {
        yield put({type: "AJAX_FAILED"});
    }
}

export default function* () {
    yield [
        takeEvery("AJAX_REQUESTED", handleAjaxRequest),
    ]
}
like image 922
Blusky Avatar asked Apr 04 '17 09:04

Blusky


1 Answers

You could utilize componentWillReceiveProps() which is called as soon as your component gets a redux property/state update. There you can react on the redux state changes and set your local component state accordingly.

In your example it would be:

componentWillReceiveProps(nextProps) {
  if (nextProps.loading !== this.props.loading &&
      nextProps.success !== this.props.success &&
      !nextProps.loading && nextprops.success) {
    this.setState({ open: false });
  }
}

This is exactly the wanted behavior you defined. Imo you should also handle other cases and set state.open more dynamically, but that's beyond the scope of the question.

For reference see here: https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops

like image 168
Frank Schmid Avatar answered Oct 23 '22 14:10

Frank Schmid