#reactjs #react-hooks #use-state
#reactjs #реагирующие хуки #use-state
Вопрос:
Я пытаюсь настроить компонент, в котором перечислены несколько заголовков. Рядом с каждым заголовком есть » «, и когда вы нажимаете на » «, появится другой компонент, содержащий больше информации. Я знаю, как это сделать, чтобы одновременно мог отображаться только один компонент, но я хотел сделать так, чтобы одновременно можно было просматривать несколько компонентов.
Пока это мой код
import React, { useState, useEffect } from "react";
import MattressUpgrade from "./CamperMods/MattressUpgrade";
const CamperModsContainer = () => {
const [iconType, setIconType] = useState({
mattressUpgrade: "",
});
const [show, setShow] = useState({
mattressUpgrade: false,
});
useEffect(() => {
setIconType({
mattressUpgrade: "fas fa-plus-square",
});
setShow({
mattressUpgrade: false,
});
}, []);
let onClickHandler = (event) => {
event.preventDefault();
let payload = event.currentTarget;
toggleShow(payload);
};
const toggleShow = (payload) => {
debugger;
if (payload.value === true) {
setIconType.payload.id("fas fa-minus-square");
setShow.payload.id(true);
} else if (payload.value === false) {
setIconType.payload.id("fas fa-plus-square");
setShow.payload.id(false);
}
};
return (
<div>
<h1>Camper Modifications</h1>
<p>
As much as we love the Wolf Pup (aka the amp;apos;Gray Ghostamp;apos;), there
are some things that we tweaked...
</p>
<div className="flex-row">
<h3>Mattress Upgrade</h3>
<button
type="button"
id={show.mattressUpgrade.key}
value={show.mattressUpgrade}
className={iconType.mattressUpgrade}
onClick={onClickHandler}
></button>
</div>
{show === true amp;amp; <MattressUpgrade />}
</div>
);
};
export default CamperModsContainer;
Проблема в том, что установка идентификатора в id={show.mattressUpgrade.key}
значение не работает. Когда я нажимаю на отладчик, toggleShow
я могу получить доступ payload.value
и получить значение false
. Но если я попытаюсь это сделать payload.id
, это вернет пустую строку, и я не могу понять, почему.
Комментарии:
1. Зачем кнопке вообще нужен an
id
? Также чего вы ожидаетеshow.mattressUpgrade.key
? Я могу сказать вам, что здесь не так, но я не совсем понимаю, какова ваша цель в проблемном коде.2. И почему вы устанавливаете такое состояние
setIconType.payload.id
?useState
возвращает функцию, вам просто нужно ее вызвать3. В настоящее время в каждом из этих useStates есть только один элемент,
mattresssUpgrade
. Но это будет еще не все. Итак, я пытался выяснить, как я могу обновить только этот конкретный элемент useState. Например, если нажать » » рядом с обновлением матраса, я бы хотел обновитьuseMattress
только состояние, а не каждый элемент, который может находиться вshow
useState.
Ответ №1:
Я полагаю, что вы ищете вычисляемые свойства, но здесь есть несколько других недоразумений, на которые стоит обратить внимание.
Общее предложение состоит в том, чтобы стараться поддерживать согласованность типов данных, когда это возможно. Преобразование между строкой и логическим значением сложно отслеживать и отлаживать. Если вы в конечном итоге переключаетесь между более сложными типами данных (объектами и т. Д.), Это становится очень подверженным ошибкам.
Первая проблема заключается в том, что show.mattressUpgrade.key
это не работает, и это никогда не будет работать. key
доступен как свойство объекта show.mattressUpgrade
, но show.mattressUpgrade
не является объектом, его false
. Вы можете развернуть и запустить приведенный ниже фрагмент, чтобы увидеть, что доступ к свойству приводит к false
результату undefined
, а назначение undefined
в качестве входных id
данных приводит к e.target.id
пустой строке.
const Example = () => {
const test = false;
console.log('test.property', test.property);
const handleChange = (e) => {
console.log(e.target.id)
}
return <input id={test.property} onChange={handleChange} />
}
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Я не могу сказать вам, как вы должны установить id
для button
‘s в вашем коде, потому что в вашем примере есть только один, но именно поэтому id не работает.
Что касается состояния обновления динамически, setShow.payload.id
это неправильный путь. setShow
это функция, а не объект. Даже если бы это было так, вы бы не ссылались на него с помощью переменной payload.id
, вы бы пытались получить доступ к буквальному вложенному свойству с именем «полезная нагрузка», а затем «идентификатор». Более того, id
не ожидается, что это будет функция, но вы все равно вызываете ее как единое целое.
Для динамического доступа к свойствам объекта используется синтаксис массива ( ojb['property']
). Тогда ваша функция будет выглядеть примерно так:
const toggleShow = (payload) => {
debugger;
if (payload.value === true) {
setIconType(prev => ({...prev, [payload.id]: "fas fa-minus-square"}));
setShow(prev => ({...prev, [payload.id]: true}));
} else if (payload.value === false) {
setIconType(prev => ({...prev, [payload.id]: "fas fa-plus-square"}));
setShow(prev => ({...prev, [payload.id]: false}));
}
};
Обратите внимание, что мы также используем функциональное обновление и распространение prev
в новый объект, чтобы сохранить любые значения, которые явно не заменяются.
Комментарии:
1. Итак, я предполагаю, что мой последующий вопрос будет заключаться в следующем: что мне следует исследовать, чтобы выяснить, как создать макет в стиле аккордеона с использованием реактивных крючков, который позволяет отображать одновременно более одного раздела? Я новичок в кодировании (очевидно) и изо всех сил пытаюсь найти примеры того, как это сделать с помощью синтаксиса hooks vs class.
2. Чем это отличается от компонента класса? Проблемы здесь на самом деле не относятся к функциональным компонентам, это общие недоразумения JavaScript, которые также могут вызвать проблемы в классе. К сожалению, у меня нет никаких рекомендаций и где найти примеры этой функциональности.