React: ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ์˜ event.preventDefault๋Š” onChange๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2017๋…„ 02์›” 17์ผ  ยท  6์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: facebook/react

๊ธฐ๋Šฅ ์„ ์š”์ฒญํ•˜๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๋ฅผ๋ณด๊ณ  ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๊ณค์ถฉ!

ํ˜„์žฌ ํ–‰๋™์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

onClick ๋ฐ onChange ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ checkbox ์œ ํ˜•์˜ input ์š”์†Œ๋ฅผ ๋ Œ๋”๋ง ํ•  ๋•Œ event.preventDefault() ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  onChange ๋Š” ์—ฌ์ „ํžˆ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. event.preventDefault() ๋Š” onClick ํ•ธ๋“ค๋Ÿฌ์—์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋™์ž‘์ด ๋ฒ„๊ทธ ์ธ ๊ฒฝ์šฐ ์žฌํ˜„ ๋‹จ๊ณ„๋ฅผ ์ œ๊ณตํ•˜๊ณ  ๊ฐ€๋Šฅํ•˜๋ฉด https://jsfiddle.net ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๋ฐฉ์‹ (ํ…œํ”Œ๋ฆฟ : https://jsfiddle.net/reactjs/69z2wepo/)์„ ํ†ตํ•ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ตœ์†Œ ๋ฐ๋ชจ๋ฅผ ์ œ๊ณตํ•˜์‹ญ์‹œ์˜ค.

http://jsfiddle.net/rf3w7apc/

์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

onClick ์ฒ˜๋ฆฌ๊ธฐ์—์„œ event.preventDefault ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด input ์š”์†Œ์˜ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ธฐ๋ณธ ์ž‘์—…์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก (๋˜๋Š” ๊ทธ ํšจ๊ณผ๋ฅผ ์ทจ์†Œ) ๋ฐฉ์ง€ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒํ•˜๋ฉด change ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์€ https://jsfiddle.net/L1eskzsq/ ๋ฅผ ์ฐธ์กฐ

์–ด๋–ค ๋ฒ„์ „์˜ React์™€ ์–ด๋–ค ๋ธŒ๋ผ์šฐ์ € / OS๊ฐ€์ด ๋ฌธ์ œ์˜ ์˜ํ–ฅ์„ ๋ฐ›์Šต๋‹ˆ๊นŒ?

๋งˆ์Šคํ„ฐ, macOS 10.12.2์˜ ๋นŒ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋˜์—ˆ์œผ๋ฉฐ ๋‹ค์Œ์—์„œ ํ™•์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • Chrome 56.0.2924.87 (64 ๋น„ํŠธ)
  • Firefox 51.0.1 (64 ๋น„ํŠธ)

Safari 10.0.2๋Š” ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ change ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๊นŒ? preventDefault ์ฒดํฌ ๋ฐ•์Šค onChange ์—์„œ ํ˜ธ์ถœ๋˜๋ฉด React์™€ ๋ธŒ๋ผ์šฐ์ € ์ƒํƒœ๊ฐ€ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค : https://codesandbox.io/s/0qpr936xkv

๋ชจ๋“  6 ๋Œ“๊ธ€

change ์ด๋ฒคํŠธ์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋Š” ChangeEventPlugin ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ topChange , ๋‹น์‹ ์˜ ์•ž์— onClick ํ•ธ๋“ค๋Ÿฌ๋„ (๋ผ๊ณ  ๊ทธ๋ž˜์„œ ์ „์— preventDefault call), ์—ฌ๊ธฐ : https://github.com/facebook/react/blob/master/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js#L338

์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์ฒดํฌ ๋ฐ•์Šค์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ํ™•์ธํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋ฉฐ, ๊ทธ๋ ‡๋‹ค๋ฉด change ์ด๋ฒคํŠธ๋ฅผ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. inputValueTracking ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด์ „ ๊ฐ’๊ณผ ๋‹ค์Œ ๊ฐ’์„ ๋น„๊ตํ•˜์—ฌ์ด ๊ฒฐ์ •์„ ๋‚ด๋ฆฝ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ https://github.com/facebook/react/blob/master/src/renderers/dom/shared/ inputValueTracking.js # L154

nextValue ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด DOM์—์„œ ์ง์ ‘ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. value = isCheckable(node) ? '' + node.checked : node.value; https://github.com/facebook/react/blob/master/src/renderers/dom/shared/inputValueTracking.js# L56

๋ฌธ์ œ๋Š” node.checked ๊ฐ’์ด์ด ์‹œ์ ์—์„œ ์ผ์‹œ์ ์œผ๋กœ true์ด๋ฏ€๋กœ ์ฒซ ๋ฒˆ์งธ ํด๋ฆญ ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

lastValue == false (์ •ํ™•ํ•จ)
nextValue == true (์ž˜๋ชป๋จ)

๋‹ค์Œ ํ™•์ธ๋ž€์„ ํด๋ฆญํ•˜๋ฉด ๊ฐ’์ด ๋‹ค์Œ๊ณผ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— change ์ด๋ฒคํŠธ๊ฐ€ ๋” ์ด์ƒ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

lastValue == true (์ž˜๋ชป๋จ)
nextValue == true (์ž˜๋ชป๋จ)

์ „๋ฐ˜์ ์œผ๋กœ ๋ฌธ์ œ๋Š” React๊ฐ€ onClick ์˜ preventDefault๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— ๋…ธ๋“œ์˜ checked ๊ฐ’์ด ๋ฌด์—‡์ธ์ง€ DOM์— ์š”์ฒญํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํŒŒํ—ค์น˜๋Š” ๋ฐ ๋„์›€์„ ์ฃผ์‹  @karelskopek ๋ฐ @Mintaffee ์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

@aweary ์ด๊ฒƒ์ด ํ•ด๊ฒฐํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?

์ด๊ฑด ์ง„์ „์ด ์—†๋‚˜์š”? React v16.2๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๋™์ž‘์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. onChange๊ฐ€ ์ฒ˜์Œ์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐ๋˜๊ณ  ํ›„์† ํด๋ฆญ์ด ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’์€ ์ด์Šˆ๋ผ๊ณ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค ..

๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๊นŒ? preventDefault ์ฒดํฌ ๋ฐ•์Šค onChange ์—์„œ ํ˜ธ์ถœ๋˜๋ฉด React์™€ ๋ธŒ๋ผ์šฐ์ € ์ƒํƒœ๊ฐ€ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค : https://codesandbox.io/s/0qpr936xkv

React 16.8.6์—์„œ ์—ฌ์ „ํžˆ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ๊ฐ€๋Šฅํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ onClick ํ•ธ๋“ค๋Ÿฌ์—์„œ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

const radios = ['one', 'two', 'three'];

class Row extends Component {
  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
    this.onChange = this.onChange.bind(this);
  }

  render() {
    const { value } = this.props;
    return (
      <div className="row">
        <div className="radio-group">
          {radios.map(radio => (
            <label key={radio} className="radio">
              <input
                type="radio"
                name="radio"
                value={radio}
                checked={radio === value}
                onClick={this.onClick}
                onChange={this.onChange}
              /><span>Radio</span>
            </label>
          ))}
        </div>
      </div>
    );
  }

  onClick(event) {
    // Check something to prevent radio change
    if (...) {
      event.preventDefault();
      return;
    }
    // Sync value in the store
    this.props.setValue(event.target.value);
  }
  onChange() {
    // We need this empty handler to suppress React warning:
    // "You provided a `checked` prop to a form field without an `onChange` handler.
    // This will render a read-only field. If the field should be mutable use `defaultChecked`.
    // Otherwise, set either `onChange` or `readOnly`"
  }
}

์ œ์–ด ๋œ ๊ตฌ์„ฑ ์š”์†Œ ๋ฅผ ์‚ฌ์šฉ

onChange(event) {
  // Check something to prevent radio change
  if (...) {
    return;
  }
  // Sync value in the store
  this.props.setDateTime(event.target.value);
}

๋” ๊ฐ„๋‹จํ•œ ์†”๋ฃจ์…˜์„ ์œ„ํ•ด onMouseDown ์ด๋ฒคํŠธ์—์„œ e.preventDefault๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ onChange๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

onMouseDown(e) { if (...) { e.preventDefault(); return; } }

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰