Как поменять чекбокс в реагировать правильно?

Как правильно изменить значение флажка?

Опция 1

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [x, setX] = useState(false);

  const soldCheckbox = ({ target: { checked } }) => {
    console.log(x, checked);
    setX(checked);
  };
  return (
    <div>
      <input type="checkbox" checked={x} onChange={soldCheckbox} />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

вариант 2

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [x, setX] = useState(false);
  console.log(x);
  return (
    <div>
      <input type="checkbox" checked={x} onChange={() => setX(!x)} />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

На самом деле, я думаю, что нет никакой разницы, но я просто хотел услышать другое мнение. Может быть, что-то я не знаю, или могут быть другие решения этой проблемы.

Ответ 1

Оба пути почти одинаковы, но первый вариант на самом деле более избыточен, давайте разберемся почему:

И первый, и второй методы реализуют controlled компоненты

Это означает, что вы предоставляете значение и способ его изменения, поэтому ответственность за обновление и контроль значений снимается с компонента.

Но почему первый путь избыточен?

На самом деле вам не нужно читать из e.target.checked потому что он всегда отражает локальное состояние x, поэтому нет необходимости читать из e.target.checked и e.target.checked обратную e.target.checked, выполнив: setX(!e.target.checked) поскольку x и e.target.checked всегда будут одинаковыми.

Предостережения

Несмотря на то, что это нормально делать onClick={e => parentHandler(e)} во встроенном выражении (функция стрелки), вы должны быть осторожны, так как передача его на вход не вызовет никаких проблем, но когда вы переходите к дочерний компонент, который реализует, например, React.memo или PureComponent, фактически он будет визуализировать компонент каждый раз, потому что всегда создается новый экземпляр функции (сигнатура одна и та же, но поверхностное сравнение всегда возвращает ложное значение, потому что они разные экземпляры), поэтому по причинам оптимизации всегда лучше всего передавать реквизиты следующим образом: <Child onClick={this.clickHandler} id={item.id}/> и на дочернем: onClick={() => this.props.onClick(this.props.id)} вместо просто: <Child onClick={e => this.onClick(item.id)}/>

Ответ 2

В этом конкретном случае я бы выбрал вариант 2, более чистый код, по моему мнению.

setX изменяет состояние, нет необходимости в функции, вызывающей setX и извлекающей значение из события, если мы знаем, что значение равно x.

Ответ 3

Я думаю, что все зависит от ситуации.

Первый вариант будет лучше, если у вас много форм и компонентов. Вы можете обрабатывать все с одним обработчиком.

const handler = (e) => {
  const { target } = e;
  const value = target.type === 'checkbox' ? target.checked : target.value;
  const { name } = target;

  setForm( f => ({ ...f, [name]: value }));
};

Во-вторых, если флажок один и приложение должно как-то реагировать на его изменение. Существует третий путь к неконтролируемым входам.

Ответ 4

Единственное отличие - чистое кодирование. Первый способ лучше, если вам нужно что-то делать, кроме изменения состояния (например, для вызова http-запроса), а второй вариант, если вам нужен только флажок для работы и сохранения его значения.

Ответ 5

Похоже, что оба ваших варианта эквивалентны. Если мы посмотрим на документацию по событию onChange, предоставленному React (а не по событию change, предоставленному html), то будет сказано:

Событие onChange ведет себя так, как вы ожидаете: при изменении поля формы это событие вызывается.

Мы намеренно не используем существующее поведение браузера, потому что onChange неправильно его поведение, и React использует это событие для обработки пользовательского ввода в режиме реального времени.

DOM Elements

Итак, просто выберите вариант, который, по вашему мнению, производит более чистый код.

Ответ 6

Поскольку вы используете состояние, лучше использовать компонент на основе классов, как показано ниже

class Checkbox extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            checkbox: false;
        }
        this.checkboxChange = this.checkboxChange.bind(this);
    }
    checkboxChange(event){
        this.setState({checkbox: event.target.checked});
    }
    render(){
        <div>
          <input type="checkbox" checked={this.state.checkbox} onChange={this.checkboxChange} />
        </div>
    }

}

const rootElement = document.getElementById("root");
ReactDOM.render(<Checkbox />, rootElement);

Ответ 7

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [x, setX] = useState(false);

  const soldCheckbox = ({ target: { checked } }) => {
    console.log(x, checked);
    setX(checked);
  };
  return (
    <div>
      <input type="checkbox" checked={x} onChange={soldCheckbox} />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Ответ 8

Я всегда выбираю option 1, потому что это более общий способ определения событий изменения поля формы. В большинстве случаев у меня есть что-то в общих компонентах формы

function SomeForm() {
   const [formData, setFormData] = useState({ name: "", accept: false });
   const onFieldChange = ({ target: { name, value, checked } }) => {
      if (typeof checked !== 'undefined') { // checking if we have a "checked" field inside target
         setFormData({ [name]: checked });
      }

      setFormData({ [name]: value });
   }

   return (
      <form>
        <input type="text" name="name" value={formData.name} onChange={onFieldChange} />
        <input type="checkbox" name="accept" checked={formData.accept} onChange={onFieldChange} />
      </form>
   )
}

Идея заключается в том, что в любом случае мы собираемся получить целевой объект DOM, который содержит как checked, так и value, поэтому мы можем сделать его универсальным.

Надеюсь это поможет