The input field lets you set the count to whatever number you type in using Redux

Viewed 459

After I type a number in the input field, the count state should reflect the input value, and as I click + or -, the count state should be adding or subtracting.

Now the typed in input value is showing on the DOM, but it's not changing the count state, and when I clicked +, it's not working as I want it.

Here's the action:

    export const incrementCount = () => {
  return { type: INCREMENT };
};

export const decrementCount = () => {
  return { type: DECREMENT };
};

export const resetCount = () => {
  return { type: RESET }
};

export const typeCount = (number) => {
  return { 
    type: TYPECOUNT,
    payload: number
   }
}

export const evenCount = () => {
  return {
    type: EVENCOUNT
  }
}

export const oddCount = () => {
  return { type: ODDCOUNT }
}

Here's the reducer:

export default (state = 0, action) => {
  switch (action.type) {
    case INCREMENT:
      return state + 1
    case DECREMENT:
      return state - 1
    case RESET:
      return state = 0
    case TYPECOUNT:
      return state = action.payload
    case EVENCOUNT:
      return state + 1
    case ODDCOUNT:
      return state + 1
    default:
      return state;
  }
};

Here's the store:

import count from "./count";

import { combineReducers } from "redux";

export default combineReducers({ count });

Here's the Counter.js import React from "react";

const Counter = ({ 
  value, 
  onIncrement, 
  onDecrement, 
  onReset, 
  onType,
  onEven,
  onOdd
}) => {

  return (
    <div>
    <p>value: {value}</p>
    <p>
      <button onClick={onIncrement}>+</button>
      <button onClick={onDecrement}>-</button>
      <button onClick={onReset}>Reset</button>
      <input onChange={onType} type="number" value={value} />
      <button onClick={onEven}>Even Count</button>
      <button onClick={onOdd}>Odd count</button>
    </p>
  </div>
)
} 

export default Counter;

Here's the CounterContainer.js

import { useSelector, useDispatch } from "react-redux"
import Counter from "../components/Counter"
import { incrementCount, decrementCount, resetCount, typeCount, evenCount, oddCount } from "../actions/counterActions"

const CounterContainer = () => {
  const count = useSelector(state => state.count)
  const dispatch = useDispatch()

  const increment = () => {
    dispatch(incrementCount())
  }

  const decrement = () => {
    dispatch(decrementCount())
  }

  const reset = () => {
    dispatch(resetCount());
  }

  const type = ({ target }) => {
    dispatch(typeCount(target.value))
  }

  const even = () => {
    if(count % 2 === 0) {
      dispatch(evenCount())
    }
  }

  const odd = () => {
    if(count % 2 === 1) {
      dispatch(oddCount())
    }
  }

  return (
    <React.Fragment>
      <Counter 
        value={count} 
        onIncrement={increment} 
        onDecrement={decrement} 
        onReset={reset}
        onType={type}
        onEven={even}
        onOdd={odd}
      />
    </React.Fragment>
  )
}

export default CounterContainer
1 Answers

Issues

Near as I could tell from all your snippets it all looked good. The only bit that looked suspect to me was the consumption of the value from the number input, which will be of type string. I copied your code into a codesandbox to confirm my suspicion.

  1. The +/- buttons work as expected
  2. Reset works
  3. The "Even Count" button works
  4. The "Odd Count" button only works for positive counts. The modulus of negative odd numbers is -1, not 1 as tested for in callbacks.

console.log(-1 % 2); // -1
console.log(-3 % 2); // -1
console.log(-5 % 2); // -1

  1. The input works to change the state, but it mutates the type so the incrementing stops working. In other words string + number -> string via concatenation, string - number -> number via type coercion.

const value = "10";

const addition = value + 5; // expect 15, number
const subtraction = value - 5; // expect 5, number

console.log(addition, typeof addition); // 105, string
console.log(subtraction, typeof subtraction); // 5, number

Solution

  1. Fix the type callback to maintain the state type invariant.

    const type = ({ target }) => {
      dispatch(typeCount(Number(target.value)));
    };
    
  2. Address negative numbers correctly in odd button callback.

    const odd = () => {
      if (Math.abs(count % 2) === 1) {
        dispatch(oddCount());
      }
    };
    

Edit the-input-field-lets-you-set-the-count-to-whatever-number-you-type-in-using-redux

Related