Второй вариант не подгрузился. Я даже не знал, что есть такое - Опциональная цепочка '?.' думал странный, какой-то тернарник)
Здесь нет тернарного выражения, то есть это не "если ? то : иначе". Это сокращенная форма записи на случай если нет объекта. То есть если ты запишешь так:
this.state.done, а объекта this.state нету, то ты получишь ошибку и твой код развалится. В классическом варианте ты должен записать this.state && this.state.done
Здесь же мы указываем знак вопроса, чтобы бабель за нас создал необходимые проверки. То есть мы пишем this.state?.done, указывая, что мы обращаемся к свойству done объекта this.state, но надо проверить если ли этот объект. Подробнее читай здесь: https://learn.javascript.ru/optional-chaining

В твоем случае при с классическим синтаксисом пришлось бы писать так:
handleCardClick = () => { this.setState({ done: !(this.state && this.state.done), }) }
Или так:
handleCardClick = () => { this.setState({ done: this.state && this.state.done ? false : true, }) }



Можешь объяснить, как работает в данном случае тернарное выражение:


handleCardClick = () => { this.setState({ done: !this.state?.done, }) }

Не понимаю почему перед .done стоит точка.
Работа со стейтем в функциональных и классовых компонентах немного отличается, в том плане, что в классовых ты работаешь с полным объектом, типа такого:
this.state = { done: false, title: "Some title", }
и можешь обращаться напрямую к его свойствам типа this.state.done

В функциональных же ты не напрямую со стейтом работаешь, а с его свойствами типа так:
const [done] = useState(false)
Во втором случае у тебя стейт как бы всегда отсутствует, есть только его значения (которые могут быть пустыми). В первом же случае (в классовых) у тебя стейт может не быть, а может и быть. То есть если ты раз задал this.setState({done: true}), то у тебя this.state уже есть всегда в течение жизни компонента. Таким образом у тебя логическая ошибка в этом условии:
if (this.state) { this.setState({ done: true, }); }
У тебя всегда есть this.state и получается, что всегда задается done: true. То есть надо было проверять
if (!this.state) { this.setState({ done: true, }); }
то есть проверять отсутствие стейта, а не его наличие. Ну, это в твоем случае. А вообще в таких случаях делают так:

handleCardClick = () => { this.setState({ done: !this.state?.done, }) }
То есть устанавливают инвертированное значение.




Есть классовый компонент, который при клике переворачивает карточку и добавляет стиль.
class Card extends React.Component { state = { done: false, } handleCardClick = () => { this.setState({ done: true, }); } render() { const {eng, rus} = this.props; const {done} = this.state; const cardClass = [s.card]; if (done) { cardClass.push(s.done); } return ( <div className={cardClass.join(' ')} onClick ={this.handleCardClick} > <div className={s.cardInner}> <div className={s.cardFront}> {eng} </div> <div className={s.cardBack}> {rus} </div> </div> </div> ); } } export default Card;

Мне нужно сделать так, чтобы после того как он открыл эту карточку, при клике опять по этой карточке он ее закрыл. Грубо говоря сбросил состояние к обычному state и вернул старое отображение. Я переписал обработчик таким образом:


handleCardClick = () => { if (this.state) { this.setState({ done: true, }); } else if (this.state === true){ return this.state } }
Но он открывать открывает, а закрыть не получается. Возможно вообще неправильно делаю, так как с контекстами классов, пока не очень хорошо разобрался. Вариант через хуки не предлагать, так как цель, как раз разобраться с классами и реалезовать - это через классовый компонент.
Дима, вот у тебя есть кусок кода:
<DropdownMenuBoxStyled> <a //href={`/city/${coordsUrl}`} onClick={toggleMenuCities} title="Пивная карта по городам" > {mainCity.name} <i className="fa fa-angle-down"></i> </a> <DropdownMenuStyled opened={citiesOpened}> {citiesList} </DropdownMenuStyled> </DropdownMenuBoxStyled>
В нем есть стайлед-компоненты DropdownMenuBoxStyled и DropdownMenuStyled, которые берутся из ./styled.ts

Надо их вынести в отдельный компонент DropdownMenu (там, скорее всего, придется переименовать компоненты DropdownMenuBoxStyled и DropdownMenuStyled, чтобы было логичней, так как сейчас получается, что компонент с более коротким названием является вложенным в компонент с более длинным названием, что противоречит интуитивнопонятному неймингу).

То есть тебе надо создать компонент DropdownMenu, чтобы ты в главном меню мог вызывать так:
<DropdownMenu {...linkProps} > {citiesList} </DropdownMenu>
linkProps - это я общий набор параметров для ссылки обозначил. Фактически же да, ты будешь перечислять явно типа такого:
<DropdownMenu name={name} href={href} title={title} {/* И т.п. */} > {citiesList} </DropdownMenu>

А в том компоненте будет типа так:
const DropdownMenu: React.FC<DropdownMenuProps> = ({ name, href, title, children, ...other }) => { /** * Здесь вся логика с citiesOpened, toggleMenuCities и т.п. */ return <DropdownMenuStyled {...other} > <a href={href} title={title} onClick={toggleMenuCities} > {name} <i className="fa fa-angle-down"></i> </a> <DropdownSubMenuStyled opened={citiesOpened}> {children} </DropdownSubMenuStyled> </DropdownMenuStyled>; }
Но здесь, как видишь, other попадает в корневой тег меню, а не в ссылку, и в данной реализации получается, что у тебя ссылка имеет на вход очень ограниченное число параметров, хотя может быть сильно больше, чем ты изначально предполагаешь. Возможно имеет смысл href, title, name вынести в отдельный параметр типа linkProps, чтобы можно было сделать так:
const DropdownMenu: React.FC<DropdownMenuProps> = ({ linkProps: { name, href, title, ...otherLinkProps }, children, ...other }) => { /** * Здесь вся логика с citiesOpened, toggleMenuCities и т.п. */ return <DropdownMenuStyled {...other} > <a href={href} title={title} onClick={toggleMenuCities} {...otherLinkProps} > {name} <i className="fa fa-angle-down"></i> </a> <DropdownSubMenuStyled opened={citiesOpened}> {children} </DropdownSubMenuStyled> </DropdownMenuStyled>; }

Тогда у тебя получится более гибкий компонент, особенное если ты найдешь способ параметру linkProps задать одной конструкцией все возможные свойства ссылок:-) (Это тебе дополнительное субзадание, которое попытайся решить, но если не получится, то не фанатей).


Николай, приветствую!

Для оценки правильности поставленной задачи, посмитри, пожалуйста, тезисы. А то может я вообще не правильно понимаю, что делаю))))

Компонент должен принимать:
- название верхнего пункта меню
- список подпунктов выпадающего меню
- отображать все это добро в верхнем меню.