React : input and state

<angeLog/>ยท2024๋…„ 2์›” 18์ผ

REACT

๋ชฉ๋ก ๋ณด๊ธฐ
5/25
post-thumbnail

๐Ÿ’ก๋…ธ๋งˆ๋“œ์ฝ”๋” ๋‹ˆ๊ผฌ์Œค์˜ ๊ฐ•์˜๋ฅผ ๋ณด๋ฉฐ ๊ณต๋ถ€ํ•˜๋Š” ์‹œ๋ฆฌ์ฆˆ์ž…๋‹ˆ๋‹ค.

unite converter(๋‹จ์œ„๋ณ€ํ™˜๊ธฐ) ๋งŒ๋“ค๊ธฐ

const root = document.getElementById("root");
const App = () => {
  return (
    <div>
    <h1 class="hi">Super Converter</h1>
    <label for="minutes">Minutes</label>
    <input type="number" placeholder="Minutes" id="minutes"/>
    <label for="hours">Hours</label>
    <input type="number" placeholder="Hours" id="hours"/>
    </div>
  );
};
ReactDOM.render(<App />, root);

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋ฌธ์ œ ์—†์–ด ๋ณด์ด๊ฒ ์ง€๋งŒ react์—์„œ๋Š” ์™„์ „ํžˆ ํ‹€๋ฆฐ ๋ฐฉ์‹์ด๋‹ค. ํ•˜์ง€๋งŒ ์ฝ˜์†”์—์„œ ์—๋Ÿฌ๋Š” ๋ณด์—ฌ์ง€์ง€ ์•Š๋Š”๋ฐ react.production.min.js์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

react.development.js๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์œ ํšจํ•˜์ง€ ์•Š์€ DOM property 'for'๊ณผ 'class'๊ฐ€ ์žˆ๋‹ค๋Š” ์—๋Ÿฌ๊ฐ€ ์ถœ๋ ฅ๋˜๋Š”๋ฐ, ์ด๊ฒƒ์ด ์™œ ๋ฌธ์ œ๊ฐ€ ๋˜๋ƒ๋ฉด javascript์—์„œ ์ด๋ฏธ ์„ ์ ๋œ ์šฉ์–ด์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
jsx์—์„œ ๋ช‡๊ฐ€์ง€ ๊ธฐ์–ตํ•ด์•ผํ•˜๋Š” ๋ถ€๋ถ„์ด ์žˆ๋Š”๋ฐ, class, for์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
๊ทธ๋ ‡๋‹ค๋ฉด jsx์—์„œ class์™€ for์€ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ•ด์•ผํ• ๊นŒ?

const root = document.getElementById("root");
const App = () => {
  return (
    <div>
      <h1 className="hi">Super Converter</h1>
      <label htmlFor="minutes">Minutes</label>
      <input type="number" placeholder="Minutes" id="minutes" />
      <label htmlFor="hours">Hours</label>
      <input type="number" placeholder="Hours" id="hours" />
    </div>
  );
};
ReactDOM.render(<App />, root);

class๋Š” className์œผ๋กœ, for์€ htmlFor๋กœ ๋Œ€์ฒดํ•ด์„œ ์ž‘์„ฑํ•ด์•ผํ•œ๋‹ค.

production ๊ณผ development์˜ ์ฐจ์ด
production์€ ๋ฐฐํฌ ๋ชจ๋“œ, development๋Š” ๊ฐœ๋ฐœ ๋ชจ๋“œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
๊ฐœ๋ฐœ๋ชจ๋“œ๋Š” ๋ฒ„๊ทธ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ๋Š” ์š”์†Œ๋ฅผ ๋ฏธ๋ฆฌ ๊ฒฝ๊ณ ํ•˜๋Š” ๊ฒ€์ฆ ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด์žˆ์ง€๋งŒ, ๋ฒˆ๋“ค ํฌ๊ธฐ๋ฅผ ์ฆ๊ฐ€์‹œ์ผœ ์•ฑ ์†๋„๋ฅผ ๋А๋ฆฌ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
๐Ÿ‘‰๐Ÿป์ฐธ๊ณ  : ๊ฐœ๋ฐœ๋ชจ๋“œ๋Š” ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ• ๊นŒ?

input์˜ state ์ถœ๋ ฅํ•˜๊ธฐ

jsx์ด ์นœ์ˆ™ํ•œ ์ด์œ ๋Š” ๋ช‡๊ฐ€์ง€ ์ฐจ์ด๋ฅผ ์ œ์™ธํ•˜๋ฉด javascript์™€ ๊ฑฐ์˜ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์ด์ „์— ๊ณต๋ถ€ํ–ˆ๋˜ react๋ฌธ๋ฒ•๊ณผ js์™€ jsx์˜ ์•ฝ๊ฐ„์˜ ์ฐจ์ด์ ์„ ๊ธฐ์–ตํ•˜๋ฉฐ input์˜ state๋ฅผ onChange์ด๋ฒคํŠธ๋กœ setMinutes๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์ „๋‹ฌ์ธ์ž event๋ฅผ ํ†ตํ•ด target์˜ value๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

const App = () => {
  const [minutes, setMinutes] = React.useState();
  const onChange = (event) => {
    setMinutes(event.target.value);
  };
  return (
    <div>
      <h1 className="hi">Super Converter</h1>
      <label htmlFor="minutes">Minutes</label>
      <input
        type="number"
        placeholder="Minutes"
        id="minutes"
        value={minutes}
        onChange={onChange}
        />
      <h4>๋„ˆ๋Š” ์ด๊ฑธ ์“ฐ๊ณ  ์‹ถ์ง€? {minutes}</h4>
      <label htmlFor="hours">Hours</label>
      <input type="number" placeholder="Hours" id="hours" />
    </div>
  );
};
ReactDOM.render(<App />, root);

๊ทธ๋Ÿฐ๋ฐ ์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ž‘๋™์€ ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.
react-dom.development.js:73 Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
๊ฑฐ๋‘์ ˆ๋ฏธํ•˜๊ณ  ๋ณธ๋ก ๋งŒ ๋งํ•œ๋‹ค๋ฉด ์ดˆ๊ธฐ๊ฐ’์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๊ธด ๋ฌธ์ œ๋ผ๋Š” ๋œป์ด๋‹ค.

const [minutes, setMinutes] = React.useState(0);

React.useState()์— ์ดˆ๊ธฐ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ณ  ์‹คํ–‰ํ•˜๋ฉด ์—๋Ÿฌ์—†์ด ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

input์˜ state์ถœ๋ ฅํ•˜๊ธฐ 2

minute๋ฅผ hours๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณธ๋‹ค.
๊ฐ„๋‹จํ•˜๋‹ค. minute์™€ ๋™์ผํ•œ value๋ฅผ hours์— ํ• ๋‹นํ•˜๊ณ , value / 60 ์„ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค.

<div>
  <h1 className="hi">Super Converter</h1>
  <label htmlFor="minutes">Minutes</label>
  <input
    type="number"
    placeholder="Minutes"
    id="minutes"
    value={minutes}
    onChange={onChange}
    />
  <label htmlFor="hours">Hours</label>
  <input
    type="number"
    placeholder="Hours"
    id="hours"
    value={minutes / 60}
    />
</div>

ํ•˜์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ž‘๋™์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ์ฝ˜์†”์— ์—๋Ÿฌ๊ฐ€ ์ƒ๊ธด๋‹ค.
id=hours๊ฐ€ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” input์ธ๋ฐ value๋Š” minutes์—์„œ ๋ฐ›์•„์˜จ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์ด๊ฒฝ์šฐ๋Š” ์ฝ˜์†”์—์„œ ์ค€ hint๋Œ€๋กœ readOnly๋ฅผ ์ถ”๊ฐ€๋กœ ์ž…๋ ฅํ•ด์ฃผ๋ฉด ํ•ด๊ฒฐ๋œ๋‹ค.

<input
  type="number"
  placeholder="Hours"
  id="hours"
  value={minutes / 60}
  readOnly
  />

value={minutes / 60}๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด minutes์˜ ๊ฐ’์— ๋”ฐ๋ผ ์†Œ์ˆซ์ ์œผ๋กœ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.
Math.round()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ์‚ฐ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜์˜ฌ๋ฆผํ•˜๋ฉฐ ์ •์ˆ˜๋กœ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ํ›จ์”ฌ ๊น”๋”ํ•˜๋‹ค.

state Resetํ•˜๊ธฐ

๋ชจ๋“ ๊ฒƒ์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด๋ณธ๋‹ค.

const [minutes, setMinutes] = React.useState(0);
const onChange = (event) => {
  setMinutes(event.target.value);
};
const reset = () => {
  setMinutes(0);
};
return (
  <div>
    <h1 className="hi">Super Converter</h1>
    <div>
      <label htmlFor="minutes">Minutes</label>
      <input
        type="number"
        placeholder="Minutes"
        id="minutes"
        value={minutes}
        onChange={onChange}
        />
      <label htmlFor="hours">Hours</label>
      <input
        type="number"
        placeholder="Hours"
        id="hours"
        value={Math.round(minutes / 60)}
        readOnly
        />
      <button onClick={reset}>์ดˆ๊ธฐํ™”</button>
    </div>
  </div>
);

reset์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋‹ด๊ณ ์žˆ๋Š” btn์„ ํด๋ฆญํ•˜๋ฉด setMinutes(0)๊ฐ€ ์‹คํ–‰๋˜๊ณ , ์ดˆ๊ธฐ๊ฐ’์ธ 0์œผ๋กœ state๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค.

state Filp ๋’ค์ง‘๊ธฐ

const [filpped, setFilpped] = React.useState(false);

๊ธฐ๋ณธ๊ฐ’์ด false์ธ state๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜๊ณ , ์ด state์— ๋”ฐ๋ผ์„œ filpํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

const onFilp = () => {
  setFilpped((current) => !current);
};
<button onClick={onFilp}>๋’ค์ง‘๊ธฐ</button>

hours์™€ minutes์˜ ํ™œ์„ฑํ™”, ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ๊ณ  ์‹œ๊ฐ„์„ ๋ถ„ ๋‹จ์œ„๋กœ, ๋ถ„์„ ์‹œ๊ฐ„ ๋‹จ์œ„๋กœ ๋ฐ”๊พธ๋Š” ๋ฒ„ํŠผ๊ณผ ํ•จ์ˆ˜ onFilp์„ ๋งŒ๋“ค์—ˆ๋‹ค. onFilp์—์„œ ์‹คํ–‰๋˜๋Š” setFilpped๋Š” ํ•จ์ˆ˜ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด current๋ผ๋Š” ์ „๋‹ฌ์ธ์ž์— ํ˜„์žฌ์˜ state๊ฐ’์„ ์•ˆ์ •์ ์œผ๋กœ ๋ฐ›์•„์˜ค๊ณ , ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋ฉด current์˜ ๋ฐ˜๋Œ€์˜ ๊ฐ’์„ current๋กœ stateUpdateํ•˜๋„๋ก ํ–ˆ๋‹ค.
current๊ฐ€ false ์ด๋ฉด true, current๊ฐ€ true์ด๋ฉด false๋กœ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.

<div>
  <label htmlFor="minutes">Minutes</label>
  <input
    type="number"
    placeholder="Minutes"
    id="minutes"
    value={minutes}
    onChange={onChange}
    />
  <label htmlFor="hours">Hours</label>
  <input
    type="number"
    placeholder="Hours"
    id="hours"
    value={Math.round(minutes / 60)}
    onChange={onChange}
    disabled
    />
  <button onClick={reset}>์ดˆ๊ธฐํ™”</button>
  <button onClick={onFilp}>๋’ค์ง‘๊ธฐ</button>
</div>

input id="minutes"์™€ input id="hours"์˜ ํ™œ์„ฑ ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ๋ฅผ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ ์‰ฝ๋„๋ก readOnly์—์„œ disabled๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค.
์ด์ œ ์‚ผํ•ญ์—ฐ์‚ฐ์ž๋ฅผ ํ™œ์šฉํ•˜์—ฌ state๋ฅผ upDateํ•ด๋ณธ๋‹ค.

//์ดˆ๊ธฐ๊ฐ’
const [filpped, setFilpped] = React.useState(false);

//์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜
const onFilp = () => {
  setFilpped((current) => !current);
};

<div>
  <h1 className="hi">Super Converter</h1>
  <div>
    <label htmlFor="minutes">Minutes</label>
    <input
      type="number"
      placeholder="Minutes"
      id="minutes"
      
      //filpped๊ฐ€ true์ด๋ฉด Math.round(minutes * 60) ์‹คํ–‰. ์•„๋‹ˆ๋ผ๋ฉด minutes๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.
      value={filpped ? Math.round(minutes * 60) : minutes}
      
      onChange={onChange}
      
      //filpped๊ฐ€ true์ผ๋•Œ disabled์ฒ˜๋ฆฌ๋œ๋‹ค.
      disabled={filpped}
      />
    <label htmlFor="hours">Hours</label>
    <input
      type="number"
      placeholder="Hours"
      id="hours"
      
      //filpped๊ฐ€ true์ด๋ฉด minutes๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ , ์•„๋‹ˆ๋ผ๋ฉด Math.round(minutes * 60) ์‹คํ–‰.
      value={filpped ? minutes : Math.round(minutes / 60)}
      
      onChange={onChange}
      //filpped๊ฐ€ false์ผ๋•Œ disabled์ฒ˜๋ฆฌ๋œ๋‹ค.
      disabled={!filpped}
      />
    <button onClick={reset}>์ดˆ๊ธฐํ™”</button>
    <button onClick={onFilp}>๋’ค์ง‘๊ธฐ</button>
  </div>
</div>

//์ „์ฒด์ฝ”๋“œ
const root = document.getElementById("root");
const App = () => {
  const [minutes, setMinutes] = React.useState(0);
  const [filpped, setFilpped] = React.useState(false);
  const onChange = (event) => {
    setMinutes(event.target.value);
  };
  const reset = () => {
    setMinutes(0);
  };
  const onFilp = () => {
    setFilpped((current) => !current);
  };
  return (
    <div>
      <h1 className="hi">Super Converter</h1>
      <div>
        <label htmlFor="minutes">Minutes</label>
        <input
          type="number"
          placeholder="Minutes"
          id="minutes"
          //value={filpped ? minutes * 60 : minutes}
          value={filpped ? Math.round(minutes * 60) : minutes}
          onChange={onChange}
          disabled={filpped}
          />
        <label htmlFor="hours">Hours</label>
        <input
          type="number"
          placeholder="Hours"
          id="hours"
          value={filpped ? minutes : Math.round(minutes / 60)}
          onChange={onChange}
          disabled={!filpped}
          />
        <button onClick={reset}>์ดˆ๊ธฐํ™”</button>
        <button onClick={onFilp}>๋’ค์ง‘๊ธฐ</button>
      </div>
    </div>
  );

์‘์šฉ

์กฐ๊ฑด์— ๋”ฐ๋ผ compornent๋ฅผ showํ•  ์ˆ˜ ์žˆ๋‹ค.

const root = document.getElementById("root");

//compornent1
function MinutesToHours() {
  const [minutes, setMinutes] = React.useState(0);
  const [filpped, setFilpped] = React.useState(false);
  const onChange = (event) => {
    setMinutes(event.target.value);
  };
  const reset = () => {
    setMinutes(0);
  };
  const onFilp = () => {
    setFilpped((current) => !current);
  };
  return (
    <div>
      <div>
        <label htmlFor="minutes">Minutes</label>
        <input
          type="number"
          placeholder="Minutes"
          id="minutes"
          value={filpped ? Math.round(minutes / 60) : minutes}
          onChange={onChange}
          disabled={filpped}
          />
        <label htmlFor="hours">Hours</label>
        <input
          type="number"
          placeholder="Hours"
          id="hours"
          value={filpped ? minutes : Math.round(minutes / 60)}
          onChange={onChange}
          disabled={!filpped}
          />
        <button onClick={reset}>์ดˆ๊ธฐํ™”</button>
        <button onClick={onFilp}>๋’ค์ง‘๊ธฐ</button>
      </div>
    </div>
  );
}
//compornent2
function KmToMiles() {
  return <h3>Km 2 Miles</h3>;
}

//compornent3
//compornent3์•ˆ์—์„œ ์กฐ๊ฑด์— ๋”ฐ๋ผ compornent1,2 render.
function App() {
  const [index, setIndex] = React.useState("2");
  const onSelect = (e) => {
    setIndex(e.target.value);
  };
  return (
    <div>
      <h1 className="hi">Super Converter</h1>
      <select value={index} onChange={onSelect}>
        <option value="0">MinutesToHours</option>
        <option value="1">KmToMiles</option>
        <option value="2">์„ ํƒํ•ด์ค˜์ž‰</option>
      </select>
      
      // jsx๋ฌธ๋ฒ•์—์„œ๋Š” {์ค‘๊ด„ํ˜ธ}์•ˆ์—์„œ javascript๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
      // ์‚ผํ•ญ์—ฐ์‚ฐ์ž๋ฅผ ์ค‘์ฒฉ์œผ๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค.
      {index === "2" ? (
        "์„ ํƒํ•ด์ค˜์ž‰"
      ) : index === "0" ? (
        <MinutesToHours />
      ) : (
        <KmToMiles />
      )}
    </div>
  );
}
ReactDOM.render(<App />, root);

CODE CHALLENGE

๋‹ˆ๊ผฌ์Œค์˜ ์ฑŒ๋ฆฐ์ง€! ํ˜ผ์ž km to mile ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค์–ด๋ณด๊ธฐ.

function KmToMiles() {
  const [kmState, setKmState] = React.useState(0);
  const [inputAble, setInputAble] = React.useState(false);
  const onChange = (e) => {
    setKmState(e.target.value);
    console.log(e.target.value);
  };
  const reset = () => {
    setKmState(0);
  };
  const filp = () => {
    setInputAble((current) => !current);
  };
  return (
    <div>
      <h3>km to mile</h3>
      <div>
        <label htmlFor="km">ํ‚ฌ๋กœ๋ฏธํ„ฐ</label>
        <input
          type="number"
          placeholder="ํ‚ฌ๋กœ๋ฏธํ„ฐ"
          id="km"
          value={inputAble ? kmState * 1.609 : kmState}
          onChange={onChange}
          disabled={inputAble}
          />
      </div>
      <div>
        <label htmlFor="mile">๋งˆ์ผ</label>
        <input
          type="number"
          placeholder="๋งˆ์ผ"
          id="mile"
          value={inputAble ? kmState : kmState * 0.609}
          onChange={onChange}
          disabled={!inputAble}
          />
      </div>
      <button onClick={reset}>์ดˆ๊ธฐํ™”</button>
      <button onClick={filp}>๋’ค์ง‘๊ธฐ</button>
    </div>
  );
}


์„ฑ๊ณตโœจ

profile
์ผ๋‹จ ํ•ด๋ณผ๊ฒŒ์š”!โœ๐Ÿป

0๊ฐœ์˜ ๋Œ“๊ธ€