0

I have a redux thunk createTodoThunk.

This thunk needs two variables accountIntId and todoListIntId required as placeholders to build the URL of the endpoint to call to create the todo.

In practice, I need that an URL changes from this to this:

- /api/accounts/:account/todo_lists/:todo_list/todos
+ /api/accounts/1/todo_lists/1/todos

The question is: how can I pass these two variables to the thunk?

More details about the thunk later.

For the moment lets go in order...

I have a form to create a todo:

const TodoForm = ({ handleSubmit, isWorking, scope, onToggle }) => {
  const idPrefix = 'todo';

  return (
    <form
      onSubmit={handleSubmit}
    >
      <Field
        component={RenderField}
        name="name"
        type="text"
        idPrefix={idPrefix}
      />
      <Field
        component={RenderField}
        name="description"
        type="textarea"
        idPrefix={idPrefix}
      />
      <button type="submit">
        {'creating' === scope ? 'Create new todo' : 'Edit todo'}
        {isWorking && <Spinner />}
      </button>
      ...
    </form>
  );
};

TodoForm.propTypes = {
  ...
};

function mapStateToProps(state, ownProps) {
  ...

  return { isWorking };
}

function mapDispatchToProps(dispatch, ownProps) {
  ...

  return { onCancel };
}

const ConnectedForm = connect(mapStateToProps, mapDispatchToProps)(TodoForm);

export default reduxForm({ form: 'todo_quick' })(ConnectedForm);

This component is used by other components that show the form to create the Todo (component TodoForm).

One of those components is TodoListPage:

class TodoListPage extends React.Component {
  componentDidMount() {
    ...
  }

  render() {
    const {
      currentAccountIntId,
      currentTodoListModel,
      ...
      onCreateTodo,
      ...
    } = this.props;
    
    ...

    return hasToRedirect ? (
      ...
    ) : (
         ...
              {... &&
                (showTodoForm ? (
                  <TodoForm
                    onSubmit={onCreateTodo}
                    ...
                  />
                ) : (
                  ...
                ))}
         ...
    );
  }
}

TodoListPage.propTypes = {
  currentAccountIntId: PropTypes.number.isRequired,
  currentTodoListIntId: PropTypes.number.isRequired,
  ...
  onCreateTodo: PropTypes.func.isRequired,
  ...
};

TodoListPage.defaultProps = { currentTodoListModel: null };

const mapStateToProps = (state, ownProps) => {
  const currentAccountIntId = parseInt(ownProps.match.params[ACCOUNT_KEY], 10);
  const currentTodoListIntId = parseInt(ownProps.match.params[TODO_LIST_KEY], 10);

  return {
    currentAccountIntId,
    currentTodoListIntId,
    currentTodoListModel: dbGetTodoListDetailsFromIntId(state, currentTodoListIntId),
    ...
  };
};

const mapDispatchToProps = {
  onCreateTodo: createTodoThunk,
  ...
};

export default connect(mapStateToProps, mapDispatchToProps)(TodoListPage);

As you can see, onSubmit={onCreateTodo} actually receives the thunk createTodoThunk (as defined in mapDispatchToProps).

The redux thunk createTodoThunk is this:

export function createTodoThunk(todo) {
  return (dispatch, getState) => {
    dispatch(createTodoLoadingAction(true));

    const token = ctxGetUserToken(getState());

    return fetch(TODOS_TODO_CREATE_ENDPOINT, token, null, HTTP_POST, todo)
      .then((response) => {
        ...
  };
}

This thunk calls the URL TODOS_TODO_CREATE_ENDPOINT. It is something like this:

/api/accounts/:account/todo_lists/:todo_list/todos

As you can see, it has two placeholders:

  • :account
  • :todo_list

So, before calling the endpoint, I need to substitute the two endpoints.

The fetch() function already does this: it is sufficient to pass an array with the substitutions to do:

export function createTodoThunk(todo) {
  return (dispatch, getState) => {
    dispatch(createTodoLoadingAction(true));

    const token = ctxGetUserToken(getState());

+    const placeholders = [
+      { replace: "account", value: accountIntId },
+      { replace: "todo_list", value: todoListIntId },
+    ];

-    return fetch(TODOS_TODO_CREATE_ENDPOINT, token, null, HTTP_POST, todo)
+    return fetch(TODOS_TODO_CREATE_ENDPOINT, token, placeholders, HTTP_POST, todo)
      .then((response) => {
        ...
  };
}

So, the question is: how do I pass accountIntId and todoListIntId to createTodoThunk()?

Ideally, I'd like to create a method in TodoForm that actually wraps createTodoThunk passing it the two arguments accountIntId and todoListIntId.

Unfortunately, after a lot of try and fails, I'm writing here because I'm not able to find a proper solution.

Any ideas?

Aerendir
  • 6,152
  • 9
  • 55
  • 108

0 Answers0