score:1

Accepted answer

you are only calling buildcontrols once, where the <input ... gets its value only that single time.

whenever react re-renders your component (because e.g. some state changes), your {controls} will tell react to render that original <input ... with the old value.

i'm not sure why you are storing your controls in a state variable? there's no need for that, and as you noticed, it complicates things a lot. you would basically require a rendercontrols() function too that you would replace {controls} with.

score:2

i'd move your inputs out of that component, and let them manage their own state out of the tipselector.

see:

https://codesandbox.io/s/naughty-http-d38w9

e.g.:

import { usestate, useeffect } from "react";
import custominput from "./input";

function tipselector({ selections, ontipchanged }) {
  const [controls, setcontrols] = usestate([]);

  //build controls
  function buildcontrols() {
    let controllist = [];
    controllist.push(<custominput />);
    controllist.push(<custominput />);
    setcontrols(controllist);
  }

  useeffect(() => {
    buildcontrols();

    return () => {
      console.log("unmounts");
    };
  }, []);

  return (
    <div>
      <span>select tip %</span>
      <div>{controls}</div>
    </div>
  );
}

export default tipselector;

import { usestate, useeffect } from "react";

function custominput() {
  const [tip, settip] = usestate("0");

  function customtipchanged(percent) {
    settip(percent);
  }

  return (
    <input
      value={tip.tostring()}
      onchange={(event) => {
        customtipchanged(event.target.value);
      }}
    ></input>
  );
}

export default custominput;


Related Query

More Query from same tag