Как поменять чекбокс в реагировать правильно?
Как правильно изменить значение флажка?
Опция 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
, поэтому мы можем сделать его универсальным.
Надеюсь это поможет