1

I am trying to update the database. So I have an input field that is disabled as default. So when you click, editing is enabled and when you click outside of the input field, it gets disabled again. What I am trying to do is update when you click outside of the input field. So, my input is like this:

const InputPrice = ({ mainPricePosts, handleChange }) => {
  const [disabled, setDisabled] = useState(true);
  const [priceValue, setPriceValue] = useState(mainPricePosts);

  function handleClick() {
    if (disabled === true) {
      setDisabled(false);
    }
  }

  return (
    <>
    <Form.Control
      type="text"
      className="price_coefficient_input"
      value={priceValue}
      onBlur={() => {
        setDisabled(true);
        handleChange(priceValue);
      }}
      onChange={handleChange(mainPricePosts)}
      readOnly={disabled}
      onClick={handleClick}
    />
    </>
  );
};

InputPrice.propTypes = {
  mainPricePosts: PropTypes.object.isRequired,
  handleChange: PropTypes.func.isRequired,
};

export default InputPrice;

And this is how I am trying to update but I am not sure if I am doing right to get the value from the input field:

const [updatePosts, setUpdatePosts] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  const [show, setShow] = useState(false);
  const [showError, setShowError] = useState(false);
  const handleClose = () => setShow(false);
  const handleCloseError = () => setShowError(false);

  const fetchIndividualPosts = async ({ value, post: { mainPricePosts, key } = {} }) => {
    console.log(value);
    try {
      setLoading(true);
      const res = await Axios({
        method: "POST",
        url: `url`,
        headers: {
          "content-Type": "application/json",
        },
        data: {
          updated_parameter: ["main_price", "small_car", key],
          updated_value: value,
        },
      });
      if (res.status === 200) {
        setUpdatePosts(res.data);
      }
      setLoading(false);
    } catch (err) {
      console.log(err.response.status);
      setError(err.response.data.error);
      setLoading(false);
    }
  }; 

  const handleChange = (mainPricePosts) => (e) => {
    fetchIndividualPosts({ mainPricePosts, value: e.target.value });
  };

This is also the curl how I can update the data:

curl -L -i -H "Content-Type: application/json" -X POST -d '{
              "updated_parameter":["100"],
              "updated_value":"0.044"
      }'  $ip''

so updated_value should be the updated input (the value after, outside is clicked) 100, should be the key of the input value.

Hope it is clear and you can help me about this problem.

Thanks for your help beforehand.

magic bean
  • 787
  • 12
  • 39

1 Answers1

0

There are many ways you can achieve what you need, but I would use following approach.

In your InputPrice component on onBlur event I would disable input by calling setDisabled(true) and then use useEffect hook to call handleChange callback if new price value and original price values are different. Because you are calling setDisabled(true), you're actually re-rendering your InputPrice component and therefore not executing handleChange callback.

Checkout code below.

  const InputPrice = ({ mainPricePosts, handleChange }) => {
  const [disabled, setDisabled] = useState(true);
  const [priceValue, setPriceValue] = useState(mainPricePosts);

  function handleClick() {
    if (disabled === true) {
      setDisabled(false);
    }
  }
  
 useEffect(() => {
    let callUpdateCallback = false;
    if (priceValue !== mainPricePosts) callUpdateCallback = true;
    if (disabled && callUpdateCallback) handleChange(priceValue);
 }, [disabled, priceValue, handleChange, mainPricePosts]);

  return (
    <>
    <Form.Control
      type="text"
      className="price_coefficient_input"
      value={priceValue}
      onBlur={setDisabled(true)}
      onChange={(e) => setPriceValue(e.target.value)}
      readOnly={disabled}
      onClick={handleClick}
    />
    </>
  );
};

InputPrice.propTypes = {
  mainPricePosts: PropTypes.object.isRequired,
  handleChange: PropTypes.func.isRequired,
};

export default InputPrice;

You call this component like this

import React from "react";
import ReactDOM from "react-dom";
import InputPrice from "./InputPrice";

function App() {
  const handleChange = (e) => {
    console.log("app handle change", e);
    // You can call your fetch here...
  };
  return (
    <div>
      <InputPrice mainPricePosts="500" handleChange={handleChange} />
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector("#root"));

Additionally there codesandbox that used to debug it, so if you need more details you can find it on the link below.

https://codesandbox.io/s/reactjs-playground-forked-8vwe2?file=/src/index.js:0-364

thug_
  • 893
  • 2
  • 11
  • 31
  • I could just have a chance to test your answer. But it says "Error: Too many re-renders. React limits the number of renders to prevent an infinite loop." – magic bean Jun 29 '21 at 10:41
  • Did you test in your code or using codesandbox link that I provided above ? I just tried on codesandbox and it is working ok. If you are trying in your code you might have issue somewhere else. – thug_ Jun 29 '21 at 11:22