colinbate / redux-form-submit-saga

Handles redux-form submissions using redux-saga
MIT License
61 stars 12 forks source link

Saga not fired #16

Open jmolero opened 7 years ago

jmolero commented 7 years ago

Hi. I have a similar problem to issue #4 . Seems none of the actions are fired even though I used the addFormSubmitSagaTo function. I also tried also adding the saga to my sagas root.

I think I followed all the steps. Here's my code:

// sagas.ts
import { demoGamesOperations } from './demo-games';
import { all } from 'redux-saga/effects';

export default function* rootSaga() {
  yield all([
    demoGamesOperations(),
  ]);
}
// reducers.ts
import demoGames from './demo-games';
import { reducer as form } from 'redux-form/immutable';

export default {
  demoGames,
  form,
};
// store.ts
import { createStore, applyMiddleware } from 'redux';
import * as withRedux from 'next-redux-wrapper';
import nextReduxSaga from 'next-redux-saga';
import createSagaMiddleware from 'redux-saga';
import { combineReducers } from 'redux-immutable';
import { fromJS } from 'immutable';
import { addFormSubmitSagaTo } from 'redux-form-submit-saga/immutable';

import reducers from 'ducks/reducers';
import allSagas from 'ducks/sagas';

const sagaMiddleWare = createSagaMiddleware();
const rootReducer = combineReducers(reducers);

const middleware = [ sagaMiddleWare ];

export function configureStore(initalState = {}) {

  const store = createStore(rootReducer, fromJS(initalState), applyMiddleware(...middleware));

  const rootSaga = addFormSubmitSagaTo(allSagas);
  store.sagaTask = sagaMiddleWare.run(rootSaga);
  return store;
}

export function withReduxSaga(BaseComponent: any) {

  return withRedux(configureStore)(nextReduxSaga(BaseComponent));
}
// signupform.ts
import * as React from 'react';
import {
  reduxForm,
  Field,
  // WrappedFieldProps,
  // FormProps,
  // InjectedFormProps,
  // SubmitHandler,
} from 'redux-form/immutable';
import styled from 'styled-components';
import Textfield from 'components/form/textfield';
import { connect } from 'react-redux';
import SignupButton from './signup-submit-button';
import validate from './validate';
import { onSubmitActions } from 'redux-form-submit-saga/immutable';

// interface RenderTextFieldProps extends WrappedFieldProps {
interface RenderTextFieldProps {
  placeholder?: string;
  type?: string;
}

const FormError = styled.p`
  top: -25px;
  position: relative;
  color: ${(props) => props.theme.colors.negative};
  margin-bottom: 0;
`;

const renderTextField = ({ input, placeholder, type, meta: { touched, error } }: any) => {

  return (
    <div>
      <Textfield {...input} placeholder={placeholder} type={type} invalid={touched && error} />
      {touched &&
        ((error &&
          <FormError>
            {error}
          </FormError>))}
    </div>
  );
};

class SignupForm extends React.Component<any> {

  public render() {

    const { handleSubmit, invalid } = this.props;
    return (
      <form onSubmit={handleSubmit}>
        <Field
          name="first_name"
          component={renderTextField}
          type="text"
          placeholder="First Name"
        />
        <Field
          name="email"
          component={renderTextField}
          type="text"
          placeholder="Email Address"
        />
        <Field
          name="password"
          component={renderTextField}
          type="password"
          placeholder="Password"
        />
        <Field
          name="password_confirmation"
          component={renderTextField}
          type="password"
          placeholder="Password Confirmation"
        />
        <button type="submit">Sign up</button>
      </form>
    );
  }
}

export default reduxForm({
  form: 'signup',
  validate,
  onSubmit: onSubmitActions('SIGNUP'),
})(SignupForm);
// operations.ts
import { signupUser } from 'services/api';
import { call, put } from 'redux-saga/effects';
import { takeLatest } from 'redux-saga';

function* signupSaga (action: any): any {
  try {
    const response = yield call(signupUser, action.payload);
    yield put({ type: 'SIGNUP_SUCCESS', payload: response });
  } catch (err) {
    yield put({ type: 'SIGNUP_FAILURE', payload: { _error: err.message } });
  }
}

export function* watchSignup() {
  yield takeLatest('SIGNUP_SUBMIT', signupSaga);
}
// api.ts
import * as unfetch from 'isomorphic-unfetch';
import { siteUrl } from 'config';
import { SignupFormValues } from 'pages/auth/signup/components/signup-form/types';
import { toJS } from 'immutable-to-js';

async function callApi(
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'DELETE',
  endpoint: string,
  body?: any,
) {

  const fullUrl = `${siteUrl}/api/${endpoint}`;

  const res = await unfetch(fullUrl, {
    method,
    body: body ? JSON.stringify(body) : null,
  });
  if (res.ok)
    return await res.json();
  else
    throw new Error(`Calling API with ${endpoint} endpoint`);
}

export const fetchDemoGames = (isMobile: boolean) => callApi('GET', `games/${isMobile ? 'mobile' : 'desktop'}`);
export const signupUser = (values: any) => callApi('POST', `users`, { user: toJS(values) });
jmolero commented 7 years ago

I added a github repo with cleaner code to reproduce the issue: https://github.com/jmolero/next-redux-form-submit-saga

Maybe the problem is because I use it in conjunction with next.js?