Home > Software design >  react functional component: After first value not able to continue type the value in input element
react functional component: After first value not able to continue type the value in input element

Time:10-03

I'm trying to update value in react functional compoenent through input element but after the first value I'm unable to type

My Code:

import React from "react";
import "./App.css";

const { useState } = React;
function App() {
    const [items, setItems] = useState([
        { value: "" },
        { value: "" },
        { value: "" },
    ]);
    const [count, setCount] = useState(0);
    const Item = React.memo(({ id, value, onChange }) => {
        return (
            <div className="item">Item
                <input
                    onChange={(e) => onChange(id, e.target.value)}
                    value={value}
                />
            </div>
        );
    });
    return (
        <div className="app">
            <h1>Parent</h1>
            <p style={{marginTop: '20px'}}>Holds state: {count}, Does't passes to it items</p>
            <p style={{marginTop: '20px'}}>{JSON.stringify(items)}</p>
            <button onClick={() => setCount((prev) => prev   1)} style={{marginTop: '20px'}}>
                Update Parent
            </button>
            <ul className="items" style={{marginTop: '20px'}}>
                {items.map((item, index) => {
                    return (
                        <Item
                            key={index}
                            id={index}
                            value={item.value}
                            onChange={(id, value) =>
                                setItems(
                                    items.map((item, index) => {
                                        return index !== id
                                            ? item
                                            : { value: value };
                                    })
                                )
                            }
                        />
                    );
                })}
            </ul>
        </div>
    );
}

export default App;

enter image description here

CodePudding user response:

You should move the Item declaration outside the App component. Having a component declaration inside another one is almost always a bad idea. Explanation below.

import React, { useState } from "react";

const Item = React.memo(({ id, value, onChange }) => {
  return (
    <div className="item">
      Item
      <input onChange={(e) => onChange(id, e.target.value)} value={value} />
    </div>
  );
});

function App() {
  const [items, setItems] = useState([
    { value: "" },
    { value: "" },
    { value: "" }
  ]);
  const [count, setCount] = useState(0);

  return (
    <div className="app">
      <h1>Parent</h1>
      <p style={{ marginTop: "20px" }}>
        Holds state: {count}, Does't passes to it items
      </p>
      <p style={{ marginTop: "20px" }}>{JSON.stringify(items)}</p>
      <button
        onClick={() => setCount((prev) => prev   1)}
        style={{ marginTop: "20px" }}
      >
        Update Parent
      </button>
      <ul className="items" style={{ marginTop: "20px" }}>
        {items.map((item, index) => {
          return (
            <Item
              key={index}
              id={index}
              value={item.value}
              onChange={(id, value) =>
                setItems(
                  items.map((item, index) => {
                    return index !== id ? item : { value: value };
                  })
                )
              }
            />
          );
        })}
      </ul>
    </div>
  );
}

export default App;

When a component definition is inside another component, React will re-declare the inner component every time the parent re-renders. This means, that any state held by the inner component will be lost. In your case, since every time there is an entirely new component, the input was not the same input as in the previous render. This means that the input that was in focus in the previous render is not present anymore, and the new input is not focused anymore.

You should also probably change

setItems(
    items.map((item, index) => {
        return index !== id ? item : { value: value };
    })
)

to

    prev.map((item, index) => {
        return index !== id ? item : { value: value };
    })
)

It's a good idea to use the function notation for set state when the new state depends on the old state value.

  • Related