#javascript #reactjs
#javascript #reactjs
Вопрос:
В принципе, у меня есть несколько кнопок. Я хочу, чтобы пользователь мог выбрать несколько кнопок.
Я попытался использовать функциональный компонент и сохранить состояние кнопки как объект с помощью крючка useState. Состояние обновляется соответствующим образом при нажатии кнопок, но реквизиты кнопки не обновляются. Я пробовал использовать эффект для повторного отображения компонента при изменении props.isActive, но это не сработало.
Используя компонент класса, это работает именно так, как задумано. Я просто пытаюсь понять, почему это так. Если кто-нибудь может дать представление, я был бы вам очень признателен. Спасибо.
Функциональный компонент
const View = (props) => {
var [buttons, setButtons] = useState([
{ name: "Small", isActive: false },
{ name: "Large", isActive: false },
]);
const handleClick = (index) => {
let tmp = buttons;
tmp[index].isActive = !tmp[index].isActive;
return setButtons(tmp);
};
return (
<div>
{buttons.map((e, index) => {
return (
<MyButtonComponent
key={index}
name={e.name}
isActive={e.isActive}
onClick={() => handleClick(index)}
/>
);
})}
</div>
);
};
Компонент класса
class View extends Component {
state = {
btn: [
{ name: "Small", isActive: false },
{ name: "Large", isActive: false },
],
};
handleClick = (index) => {
let tmp = this.state.btn;
tmp[index].isActive = !tmp[index].isActive;
return this.setState({ ...this.state, btn: tmp });
};
render() {
return (
<div>
{this.state.btn.map((e, index) => {
return (
<MyButtonComponent
key={index}
name={e.name}
isActive={e.isActive}
onClick={() => this.handleClick(index)}
/>
);
})}
</div>
);
}
}
Ответ №1:
Вы изменяете свой старый массив, а затем устанавливаете состояние с помощью измененного массива. Это не очень хорошая идея в react, независимо от того, используете ли вы компоненты класса или функциональные компоненты. Компонент класса позволяет вам избежать этого, но функциональный компонент сравнивает состояние до с состоянием после и видит, что это один и тот же массив, поэтому он пропускает рендеринг.
Чтобы исправить это, вы должны создать новое состояние вместо изменения старого. Измените это:
let tmp = buttons;
tmp[index].isActive = !tmp[index].isActive;
return setButtons(tmp);
К этому:
// Create a copy of the array
let tmp = [...buttons];
// Also copy the item you want to change
tmp[index] = {
...tmp[index],
active: !tmp[index].active
}
setState(tmp);
Комментарии:
1. Ааааа понял, в этом есть смысл. Спасибо. Ваше решение работает прекрасно 🙂
Ответ №2:
Вы обновляете ссылку и устанавливаете ту же ссылку на состояние (setButtons(tmp))
, которое react thinks
, array не изменилось из-за неглубокого сравнения. Вам нужно использовать новую ссылку. Например, следующее
let tmp = buttons; <-- problem is here, reference
tmp[index].isActive = !tmp[index].isActive;
return setButtons(tmp); <-- and updating same `reference`
const handleClick = (index) => {
buttons[index].isActive = !buttons[index].isActive;
return setButtons([...buttons]); <-- this will work
};
Комментарии:
1. Спасибо за ваше объяснение, я ценю это. Это тоже отлично работает!