How can I convert a string to a number inside of a useState Hook?

Viewed 1707

I am trying to convert data from a string to a number before it is inputted so that I can perform mathematical calculations on the data later.

I tried to use parseInt inside of my useState hook but I received the following error: ReferenceError: can't access lexical declaration 'score' before initialization

import React, { Fragment, useState } from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { addGame } from '../../actions/game';

const GameInput = ({ addGame }) => {
  const [formData, setFormData] = useState({
    score: parseInt(score, 10),
    strikes: parseInt(strikes, 10),
    spares: parseInt(spares, 10),
    openFrames: parseInt(openFrames, 10),
  });

  // Destructure formData
  const { score, strikes, spares, openFrames } = formData;

  // Input Method to change state
  const onChange = (e) =>
    setFormData({ ...formData, [e.target.name]: e.target.value });

  // onSubmit Form Method
  const onSubmit = (e) => {
    e.preventDefault();
    addGame(formData);
  };

  return (
    <Fragment>
      <h1>Record Your Stats</h1>

      <form onSubmit={(e) => onSubmit(e)}>
        <div>
          <input
            type='text'
            placeholder='Score'
            name='score'
            value={score}
            onChange={(e) => onChange(e)}
          />
          <small>Your score for this game</small>
        </div>
        <div>
          <input
            type='text'
            placeholder='Stikes'
            name='strikes'
            value={strikes}
            onChange={(e) => onChange(e)}
          />
          <small># of Strikes hit this game</small>
        </div>
        <div>
          <input
            type='text'
            placeholder='Spares'
            name='spares'
            value={spares}
            onChange={(e) => onChange(e)}
          />
          <small># of Spares hit this game</small>
        </div>
        <div>
          <input
            type='text'
            placeholder='Open Frames'
            name='openFrames'
            value={openFrames}
            onChange={(e) => onChange(e)}
          />
          <small># of frames with pins left standing</small>
        </div>

        <input type='submit' />
        <Link className='btn btn-light my-1' to='/profile'>
          Back to Profile
        </Link>
      </form>
    </Fragment>
  );
};

GameInput.propTypes = {
  addGame: PropTypes.func.isRequired,
};

export default connect(null, { addGame })(GameInput);
1 Answers

The state isn't defined yet so it's not accessible. You are setting the initial state, so just declare it with the type you want. score, strikes, spares, and openFrames haven't been declared or defined yet, so they can't be used.

Seems you are really wanting to parse the input strings back to number types when updating state. To maintain your state invariant you could/should do this conversion in your onChange handler.

// Input Method to change state
const onChange = (e) => {
  const { name, value } = e.target;
  setFormData({ ...formData, [name]: parseInt(value, 10) }); // Or Number(value)
};

Provide valid initial state.

const [formData, setFormData] = useState({
  score: 0,
  strikes: 0,
  spares: 0,
  openFrames: 0,
});
Related