3

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);
melly18
  • 87
  • 3
  • 11
  • 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. – Drew Reese Apr 26 '21 at 18:08
  • You've created a logical impossibility. Creating `formData` requires using `score`, and creating `score` requires using `formData`. Where does any actual data come from here? – David Apr 26 '21 at 18:09
  • @David It's inputted by the user in a form on the client side. – melly18 Apr 26 '21 at 18:10
  • @tydangelo18: Not *before the form renders* it isn't. Did you mean to set initial values to some default instead? – David Apr 26 '21 at 18:11
  • @David originally inside my useState hook, the initial state were empty strings. – melly18 Apr 26 '21 at 18:12
  • @tydangelo18: That sounds like it solves the problem. Why was it changed? At worst if you want them to be numeric values you can default them to `0` or `undefined`. But they should probably stay strings for the form element values and be converted to numbers downstream when they need to be. – David Apr 26 '21 at 18:13
  • @David My issue is that once strikes, spares, score, and openFrames are inputted, they are strings, but in another component I am trying to perform mathematical calculations on score, strikes, spares, and openFrames, but it returns NaN since they are strings. I can't figure out where to convert them to numbers. – melly18 Apr 26 '21 at 18:15

1 Answers1

2

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,
});
Drew Reese
  • 165,259
  • 14
  • 153
  • 181