skip to Main Content

I have a small React app.
The aim of this project is to manage products.
These products contain features.
The example below is for a page used to configure prices for product features.

export function App() {

  // This state is manage by HTTP calls
  const [features_dict, set_features_dict] = useState({"features": []});

  // I want to display the details of my list
  return (
    <div className={s.main_container}>
      <FeaturesDetail FeaturesDict={features_dict} />
    </div>
  )


}

My FeaturesDetail component

export function FeaturesDetail({FeaturesDict}) {

  const listFeaturesElement = FeaturesDict.features.map(feature =>
    <tbody>
      <td>{feature.name}</td>
      <td>
        <input
            type="number"
            value={feature.price}
        />
      </td>
      <td><button>Update</button></td>
    </tbody>
  );

  return (
    <div>
      <table>
        <thead>
          <td>Name</td>
          <td>Price</td>
        </thead>
        {listIngredientsElement}
      </table>
    </div>
  );

}

It seems like a React event prevent me to modify my input field.

My final goal is to update the features_dict state and run a function to send it in a HTTP call.
This HTTP call’ll update the product configuration in back-end database.

2

Answers


  1. You need to set onChange or onInput event on the input element to a function which will update the price, Define the function at the App component and pass it to FeaturesDetail component as a prop ( to be in the place where the state is defined ), this function takes two parameters, the first parameter is a unique identifier for the product, for example, the name or the id, the second parameter is the new price, then update the product which has this unique identifier with the new price.

    App.js

    export function App() {
      const [featuresDict, setFeaturesDict] = useState({ "features": [] });
    
      const updateFeaturePrice = (featureName, newPrice) => {
        const updatedFeatures = featuresDict.features.map(feature => {
          if (feature.name === featureName) {
            return { ...feature, price: newPrice };
          }
          return feature;
        });
    
        setFeaturesDict({ features: updatedFeatures });
      };
    
      return (
        <div className={s.main_container}>
          <FeaturesDetail featuresDict={featuresDict} onPriceChange={updateFeaturePrice} />
        </div>
      );
    }
    

    FeaturesDetail.js

    export function FeaturesDetail({ featuresDict, onPriceChange }) {
    
      const listFeaturesElement = featuresDict.features.map((feature, index) =>
        <tr key={index}>
          <td>{feature.name}</td>
          <td>
            <input
              type="number"
              value={feature.price}
              onChange={(e) => onPriceChange(feature.name, e.target.value)}
            />
          </td>
          <td><button>Update</button></td>
        </tr>
      );
    
      return (
        <div>
          <table>
            <thead>
              <tr>
                <th>Name</th>
                <th>Price</th>
              </tr>
            </thead>
            <tbody>
              {listFeaturesElement}
            </tbody>
          </table>
        </div>
      );
    }
    

    Also, I suggest that you rename your variables as camelCase for javascript standards

    Login or Signup to reply.
  2. Why it does not work

    There are either controlled inputs or uncontrolled input fields. Whenever you pass in a value attribute to an input field in React, you indicate that it is controlled and you will be handling the value change

    <input type="text" value={inputVal} />
    

    The above means that your code should update inputVal so that the input field shows it.

    And for that you have to add a change handler :

    <input type="text" value={inputVal} onChange={changeHandler}/>
    

    This changeHandler updates the inputVal and triggers a rerender to show the updated inputVal in the input text field.

    The above is for controlled. If you think that the field is better of uncontrolled, then all you have to do is change to this:

     <input type="number" defaultValue={feature.price} />
    

    Simple demo

    In your case you want to have a controlled field and update its state using handlers so please follow the guide linked above.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search