0

I am a React beginner but I did a very basic form component that does not work! It is this. What is the trouble? Maybe the value={prop.value}?

ReactDOM
    .createRoot(document.getElementById('root'))
    .render(<App />);

function App() {
    const data = [
        {
            type: 'text',
            name: 'name',
            label: 'Name',
            value: 'Alfred'
        },
        {
            type: 'number',
            name: 'amount',
            label: 'Amount',
            value: 23
        },
        {
            type: 'date',
            name: 'birthday',
            label: 'Date',
            value: '1987-02-01'
        }
    ];

    return <Form data={data} />;
}

function Form(props) {
    let [data, setData] = React.useState(props.data);
    const handleChange = (e) => {
        let elem = e.target;
        setData((data) => {
            const prop = data[elem.dataset.index];
            console.log('Input \'' + prop.name + '\' becomes from \'' + prop.value + '\' to \'' + elem.value + '\'');
            data[elem.dataset.index].value = elem.value;
            return data;
        });
    };

    return (
        <form>
            {data.map((prop, i) => {
                const id = "input-" + prop.name;
                return (
                    <div key={prop.name}>
                        <label htmlFor={id}>{prop.label}</label>
                        <span>: </span>
                        <input
                            type={prop.type}
                            id={id}
                            value={prop.value}
                            onChange={handleChange}
                            data-index={i}
                        />
                    </div>
                );
            })}
        </form>
    );
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id="root"></div>

2
  • Thank you, @nick-vu! Sorry, I did not know if there was some Babel transpiler here. Commented Oct 18, 2022 at 8:36
  • 1
    No problems!~ Everyday we learn :D Commented Oct 18, 2022 at 8:39

1 Answer 1

1

React's state is immutable, so you cannot modify the array data directly.

You have to change return data to return [...data] which is to clone your array to a new value in setData of handleChange

ReactDOM
    .createRoot(document.getElementById('root'))
    .render(<App />);

function App() {
    const data = [
        {
            type: 'text',
            name: 'name',
            label: 'Name',
            value: 'Alfred'
        },
        {
            type: 'number',
            name: 'amount',
            label: 'Amount',
            value: 23
        },
        {
            type: 'date',
            name: 'birthday',
            label: 'Date',
            value: '1987-02-01'
        }
    ];

    return <Form data={data} />;
}

function Form(props) {
    let [data, setData] = React.useState(props.data);
    const handleChange = (e) => {
        let elem = e.target;
        setData((data) => {
            const prop = data[elem.dataset.index];
            console.log('Input \'' + prop.name + '\' becomes from \'' + prop.value + '\' to \'' + elem.value + '\'');
            data[elem.dataset.index].value = elem.value;
            return [...data]; //the change is here
        });
    };

    return (
        <form>
            {data.map((prop, i) => {
                const id = "input-" + prop.name;
                return (
                    <div key={prop.name}>
                        <label htmlFor={id}>{prop.label}</label>
                        <span>: </span>
                        <input
                            type={prop.type}
                            id={id}
                            value={prop.value}
                            onChange={handleChange}
                            data-index={i}
                        />
                    </div>
                );
            })}
        </form>
    );
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Sign up to request clarification or add additional context in comments.

7 Comments

I didn't modify the array data directly: I try to change using useState. I don't understand the difference. If I return an array by callback, React must to know that it is the new one. :'(
You can read this article for understanding your situation better :D
I know the JavaScript behavior. To re-render the view, React needs a different reference of the returned array in useState, right?
yeah that's true! @MiquelAl.Vicens
Then, for now, I don't like React! xD
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.