4

I intend to create a simple counter using react redux in typescript.

I have defined my store with actions and reducers in the following manner but not sure how to invoke dispatch with a specific action

import * as React from 'react';
import { createStore, Action, Reducer } from 'redux';

export interface CounterState {
    counter: number;
}

export enum ActionTypes {
    INCREMENT = 'increment',
    DECREMENT = 'decrement'
}

export interface IncAction { type: ActionTypes.INCREMENT }
export interface DecAction { type: ActionTypes.DECREMENT }

export type CounterAction = IncAction | DecAction;

const reducer: Reducer<CounterState> = (state: CounterState = {counter: 0}, action: CounterAction) => {
    switch (action.type) {
        case ActionTypes.INCREMENT:
            return { ...state, counter: state.counter + 1};
        case ActionTypes.DECREMENT:
            return { ...state, counter: state.counter - 1};
        default:
            return state;
    }
};

let store = createStore(reducer, { counter: 0 });

Following is how my react component Counter looks like

interface IProps {}

interface IState {}

export default class Counter extends React.Component<IProps, IState> {

private unsubscribe: Function;

constructor(props: IProps, context?: any) {
    super(props, context);
}

componentDidMount() {
    this.unsubscribe = store.subscribe(() => this.render());
}

componentWillUnmount() {
    this.unsubscribe();
}

render() {
    const { counter } = store.getState();
    return (
        <div>
            <p>
                <label>Counter: </label><b>#{counter}</b>
            </p>
            <button onClick={e => store.dispatch('increment') }>+</button>
            <span style={{ padding: "0 5px" }} />
            <button onClick={e => store.dispatch('decrement') }>-</button>
        </div>
    );
}

}

I am getting following error -

ERROR in [at-loader] ./src/components/Counter.tsx:63:54 TS2345: Argument of type '"increment"' is not assignable to parameter of type 'AnyAction'.

ERROR in [at-loader] ./src/components/Counter.tsx:65:54 TS2345: Argument of type '"decrement"' is not assignable to parameter of type 'AnyAction'.

2 Answers 2

3

Look at the actual type definition of Action and AnyAction:

export interface Action {
  type: any;
}

export interface AnyAction extends Action {
  // Allows any extra properties to be defined in an action.
  [extraProps: string]: any;
}

It needs to be an object and it must have a type property NOT just a string.

You need an action creator that returns at a minimum an object with a type property. You can also pass this object directly, which is what I assume you where attempting to do:

store.dispatch({type: ActionTypes.INCREMENT})

I would also recommend using the connect HOC to connect state to your component since doing const { counter } = store.getState(); will not trigger a re-render when the counter value in your store changes. If you want a more basic example:

...
  this.unsubscribe : () => void

  componentDidMount() {
    this.unsubscribe = store.subscribe(() => this.setState({ store.getState() }))
  }

  componentWillUnmount() {
    this.unsubscribe()
  }
...

Then reference the component's local state in render via const { counter } = this.state;

Sign up to request clarification or add additional context in comments.

2 Comments

I got it solved by passing store.dispatch({type: ActionTypes.INCREMENT}). Also had to destructure store.getState() in { counter } but still counter remains 0 i:(
I have updated my answer, for anything more complicated you really need to look at using react-redux --> github.com/reduxjs/react-redux
1

I "fixed" this by doing this:

const _ = (state: any = 0, _: AnyAction) => state;
const root = combineReducers({
    _,
    applicationStatusReducer,
    ...
});

It seems to fix the issue if you just add an empty reducer with the action type of "AnyAction" to it.

Obviously this isn't actually fixing the underlying issue, but for people who are content with the result of the fix above, this is a dirty way to do it.

Use at your own discretion.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.