Increment and decrement counter with input using redux

Viewed 815

I want to increase and decrease the counter.counter1 and counter.counter2.innerCount by input value. Here is the error I found now

enter image description here

I am weak at destructing object etc. and now learning for it.
Could provide me any advice or code? Especially for increment and decrement for innerCount. Much appreciate.

actionCreators.js

import * as actionTypes from "../actionTypes";

export const incrementCounter1 = () => {
  return {
    type: ActionTypes.INCREMENT_COUNTER_1,
  };
};

export const decrementCounter1 = () => {
  return {
    type: ActionTypes.DECREMENT_COUNTER_1,
  };
};

export const incrementByAmount = (amount) => {
  return {
    type: ActionTypes.INCREMENT_BY_AMOUNT,
    amount:amount,
  };
};

reducer.js

import * as actionTypes from "../actionTypes";

const INITIAL_STATE = {
  counter: {
    counter1: 0,
    counter2: {
      innerCount: 0,
    },
  },
};

export const Auth = (state = INITIAL_STATE, action) => {
  const { type, payload } = action;
  let a;
  switch (type) {
    case ActionTypes.INCREMENT_COUNTER_1:
      a = {
        ...state,
        counter: {
          ...state.counter,
          counter1: state.counter.counter1 +=1,
        },
      };
      return a;
    case ActionTypes.DECREMENT_COUNTER_1:
      a = {
        ...state,
        counter: {
          ...state.counter,
          counter1: state.counter.counter1 -=1,
        },
      };
      return a;
    case ActionTypes.INCREMENT_BY_AMOUNT:
      a = {
        ...state,
        counter: {
          ...state.counter,
          counter1: state.counter.counter1 +=payload,
        },
      };
      return a;
    default:
      return state;
  }
};

export default Auth;

mainPage.js

import React, { useState } from "react";
import { View, Text, StyleSheet, Button, TextInput } from "react-native";
import {
  incrementCounter1,
  decrementCounter1,
  incrementByAmount,
} from "./states/redux/ActionCreators/auth";
import { connect } from "react-redux";


const Counter = ({
  counterRedux,
  incrementCounter1,
  decrementCounter1,
  incrementByAmount,
}) => {
  const [amount, setAmount] = useState('');

  return (
    <View>
      <Text style={styles.text}>Input text for changing</Text>

      <Button title="INCREMENT" onPress={() => incrementCounter1()} />
      <Button title="DECREMENT" onPress={() => decrementCounter1()} />

      <View>
        <Text style={styles.Atext}>Enter amount to increase:</Text>
        <TextInput style={styles.input} value={amount} onChangeText={(a) => setAmount(a)} />
        <Text style={styles.Atext}>Amount: {amount}</Text>
        <Button title='Add Amount' onPress={(amount)=>incrementByAmount(amount)}></Button>
      </View>

      <View>
        <Text style={styles.Atext}>First Counter: {counterRedux.counter1}</Text>
      </View>
    </View>
  );
};

const mapStateToProps = (state) => {
  return {
    counterRedux: state.counter,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    incrementCounter1: () => dispatch(incrementCounter1()),
    decrementCounter1: () => dispatch(decrementCounter1()),
    incrementByAmount: (amount) => dispatch(incrementByAmount(amount)),
  };
};


const styles = StyleSheet.create({
  text: {
    fontSize: 25,
  },
  Atext: {
    fontSize: 20,
  },
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  input: {
    borderWidth: 1,
    borderColor: "#777",
    padding: 8,
    margin: 10,
    width: 200,
  },
  button: {
    backgroundColor: "#fff",
    fontSize: 15,
  },
});

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

actionTypes.js

export const INCREMENT_BY_AMOUNT = 'INCREMENT_BY_AMOUNT';
export const INCREMENT_COUNTER_1 = 'INCREMENT_COUNTER_1';
export const DECREMENT_COUNTER_1 = 'DECREMENT_COUNTER_1';
1 Answers

Your first issue is here: <Button title='Add Amount' onPress={(amount)=>incrementByAmount(amount)}></Button>.
What you are doing is passing to incrementByAmount the argument passed by onPress which is not at all the amount you expect, but a PressEvent object.
In order to receive the amount you expect, you need to do this: <Button title='Add Amount' onPress={() => incrementByAmount(amount)}></Button> so you get the amount from useState.

Also you definitely don't need to have three actions for your counter, a simpler way to do it would be to have an updateAmount function to which you pass as payload a type that would be "increment" or "decrement", and an amount.
An even simpler way would be to only have an amount and pass either a negative or a positive value to it.
For your increment and decrement buttons, you would simply need to pass 1 or -1 as amount.

Your second issue is that you are mutating your state in your reducer with the += and -= operators.
Here is your fixed reducer (I will let you implement the changes I suggested earlier though):

import * as actionTypes from "../actionTypes";

const INITIAL_STATE = {
  counter: {
    counter1: 0,
    counter2: {
      innerCount: 0,
    },
  },
};

export const Auth = (state = INITIAL_STATE, action) => {
  const { type, payload } = action;

  switch (type) {
    case ActionTypes.INCREMENT_COUNTER_1:
      return {
        ...state,
        counter: {
          ...state.counter,
          counter1: state.counter.counter1 + 1,
        },
      };
    case ActionTypes.DECREMENT_COUNTER_1:
      return {
        ...state,
        counter: {
          ...state.counter,
          counter1: state.counter.counter1 - 1,
        },
      };
    case ActionTypes.INCREMENT_BY_AMOUNT:
      return {
        ...state,
        counter: {
          ...state.counter,
          counter1: state.counter.counter1 + payload,
        },
      };
    default:
      return state;
  }
};

export default Auth;

I removed the a variable that wasn't needed and changed the += operator to + and the -= operator to - so your state isn't mutated.

Your third issue is that you are destructuring a variable payload while it is called amount in your action creator.
Also don't forget that you are getting a string from <TextInput> and not a number.

Finally you import your action types as actionTypes but use them as ActionTypes.

Related