reactjsreact-componentrating-system

ReactStars component can't set useState - calls TypeError: Cannot read properties of undefined (reading 'name')


I'm quite new to React and can't seem to figure out how to resolve this issue. Maybe a stupid question but here it goes.

I'm trying to make a system where each Person can add skills and a rating of those skills. Each array consist of a skill element as a string and a star element as an integer. I've made some dynamic inputfields with an add and a remove function for more/less inputfields.

For each inputfield I have an onchange function handleChangeInput and this works fine with skills as this is has a property of "name".

Now when trying to fetch the value from ReactStars I get the error: Uncaught TypeError: Cannot read properties of undefined (reading 'name'). This error is called from the handleChangeInput function. ReactStars doesn't have any property of type either.

How will I be able to fetch the value from ReactStars, if it's even possible? I want to set the useState of inputfields with the values of skill and stars of course.

Image of the TypeError.

The component I use is: react-rating-stars-component

https://www.npmjs.com/package/react-rating-stars-component

Hope this explains the problem. Otherwise let me know. Thanks.

const [data, setData] = useState({});
const [inputField, setInputField] = useState([{ skill: "", stars: 0 }]);

const handleChangeInput = (index, event) => {
    const values = [...inputField];
    values[index][event.target.name] = event.target.value;
    setInputField(values);
    setData(values);
  };

const handleAddFields = () => {
    setInputField([...inputField, { skill: "", stars: 0 }]);
  };

  const handleRemoveFields = (index) => {
    const values = [...inputField];
    console.log(inputField.length);
    values.splice(index, 1);
    setInputField(values);
    setData(values);
  };

return(
       <div>
         {inputField?.map((inputField, index) => (
            <div key={index}>
              <Row>
                <Col xs={5} md={5}>
                  <Form.Group as={Col}>
                    <Form.Control
                      className="mb-3"
                      type="text"
                      id="skill"
                      name="skill"
                      value={inputField?.skill}
                      onChange={(event) => handleChangeInput(index, event)}
                    />
                  </Form.Group>
                </Col>
                <Col xs={4} md={4}>
                  <Form.Group>
                      <ReactStars
                        type="number"
                        name="stars"
                        count={5}
                        size={24}
                        id="stars"
                        onChange={(event) => handleChangeInput(index, event)}
                        color="rgba(230, 230, 230, 255)"
                        emptyIcon={<i className="fa-solid fa-star"></i>}
                        filledIcon={<i className="fa-solid fa-star"></i>}
                        value={inputField.stars}
                      />
                    </Form.Group>
                </Col>
                <Col xs={3} md={3}>
                  <div className="btn-section">
                    <button
                      type="button"
                      className="round-btn"
                      onClick={() => handleAddFields()}
                    >
                      <i className="fa-solid fa-plus"></i>
                    </button>
                    <button
                      type="button"
                      className="round-btn"
                      onClick={() => handleRemoveFields(index)}
                    >
                      <i className="fa-solid fa-minus"></i>
                    </button>
                  </div>
                </Col>
              </Row>
            </div>
          ))}
        </div>
);

Solution

  • The package passes the new value, not an event containing it.

    You can instead simply bind the change handler differently in each case such that the context you need is passed through:

    
    const [data, setData] = useState({});
    const [inputField, setInputField] = useState([{ skill: "", stars: 0 }]);
    
    const handleChangeInput = (index, name, value) => {
        const values = [...inputField];
        values[index][name] = value;
        setInputField(values);
        setData(values);
      };
    
    const handleAddFields = () => {
        setInputField([...inputField, { skill: "", stars: 0 }]);
      };
    
      const handleRemoveFields = (index) => {
        const values = [...inputField];
        console.log(inputField.length);
        values.splice(index, 1);
        setInputField(values);
        setData(values);
      };
    
    return(
           <div>
             {inputField?.map((inputField, index) => (
                <div key={index}>
                  <Row>
                    <Col xs={5} md={5}>
                      <Form.Group as={Col}>
                        <Form.Control
                          className="mb-3"
                          type="text"
                          id="skill"
                          name="skill"
                          value={inputField?.skill}
                          onChange={(event) => handleChangeInput(index, 'skill', event.target.value)}
                        />
                      </Form.Group>
                    </Col>
                    <Col xs={4} md={4}>
                      <Form.Group>
                          <ReactStars
                            type="number"
                            name="stars"
                            count={5}
                            size={24}
                            id="stars"
                            onChange={(newValue) => handleChangeInput(index, 'stars', newValue)}
                            color="rgba(230, 230, 230, 255)"
                            emptyIcon={<i className="fa-solid fa-star"></i>}
                            filledIcon={<i className="fa-solid fa-star"></i>}
                            value={inputField.stars}
                          />
                        </Form.Group>
                    </Col>
                    <Col xs={3} md={3}>
                      <div className="btn-section">
                        <button
                          type="button"
                          className="round-btn"
                          onClick={() => handleAddFields()}
                        >
                          <i className="fa-solid fa-plus"></i>
                        </button>
                        <button
                          type="button"
                          className="round-btn"
                          onClick={() => handleRemoveFields(index)}
                        >
                          <i className="fa-solid fa-minus"></i>
                        </button>
                      </div>
                    </Col>
                  </Row>
                </div>
              ))}
            </div>
    );