Dynamic object keys... Cannot create property on string

I'm trying to make an input automatically store its value in an object. The key should be the input's id. Ex: {screen1_input1: 'whatever'}. The first character does that. The second character crashes with "TypeError: Cannot create property on string". I think I see what's happening but I don't know how to fix it.

import { useState } from 'react'

function Demo() {
    const [contentData, setContentData] = useState({})
    
    const onChange = (e) => {
        let oldData = contentData
        setContentData(oldData[e.target.id] = e.target.value)
        console.log('*')
    }
    
    const Screen1 = () => {
        return (
            <>
                <input type="text" id="screen1_input1" onChange={onChange} />
            </>
        )
    }
    
    return (
        <>
            <h2 className="Demo">
                {Screen1()}
            </h2>
        </>
    )
}

export default Demo

2 answers

  • answered 2021-03-03 02:21 CertainPerformance

    There are 2 problems.

    • The assignment operator resolves to a value of the value assigned. So
    setContentData(oldData[e.target.id] = e.target.value)
    

    is like

    oldData[e.target.id] = e.target.value;
    setContentData(e.target.value)
    

    which is causing issues because in the next render, contentData becomes a string instead of the object.

    • Never mutate state in React. Instead, create a new object:
    const onChange = (e) => {
        setContentData({
            ...contentData,
            [e.target.id]: e.target.value
        });
    };
    

  • answered 2021-03-03 02:23 bcjohn

    setContentData(oldData[e.target.id] = e.target.value) is not a valid format. You can create a newData object to copy the last contentData and add a new dynamic key-value.

    const onChange = (e) => {
        const newData = {
          ...contentData,
          [e.target.id]: e.target.value
        }
        setContentData(newData)
        console.log('*')
    }