Есть классовый компонент, который при клике переворачивает карточку и добавляет стиль.
Мне нужно сделать так, чтобы после того как он открыл эту карточку, при клике опять по этой карточке он ее закрыл. Грубо говоря сбросил состояние к обычному state и вернул старое отображение. Я переписал обработчик таким образом:
Но он открывать открывает, а закрыть не получается. Возможно вообще неправильно делаю, так как с контекстами классов, пока не очень хорошо разобрался. Вариант через хуки не предлагать, так как цель, как раз разобраться с классами и реалезовать - это через классовый компонент.
Работа со стейтем в функциональных и классовых компонентах немного отличается, в том плане, что в классовых ты работаешь с полным объектом, типа такого:
и можешь обращаться напрямую к его свойствам типа this.state.done
В функциональных же ты не напрямую со стейтом работаешь, а с его свойствами типа так:
Во втором случае у тебя стейт как бы всегда отсутствует, есть только его значения (которые могут быть пустыми). В первом же случае (в классовых) у тебя стейт может не быть, а может и быть. То есть если ты раз задал this.setState({done: true}), то у тебя this.state уже есть всегда в течение жизни компонента. Таким образом у тебя логическая ошибка в этом условии:
У тебя всегда есть this.state и получается, что всегда задается done: true. То есть надо было проверять
то есть проверять отсутствие стейта, а не его наличие. Ну, это в твоем случае. А вообще в таких случаях делают так:
То есть устанавливают инвертированное значение.
Можешь объяснить, как работает в данном случае тернарное выражение:
Не понимаю почему перед .done стоит точка.
Здесь нет тернарного выражения, то есть это не "если ? то : иначе". Это сокращенная форма записи на случай если нет объекта. То есть если ты запишешь так:
this.state.done, а объекта this.state нету, то ты получишь ошибку и твой код развалится. В классическом варианте ты должен записать this.state && this.state.done
Здесь же мы указываем знак вопроса, чтобы бабель за нас создал необходимые проверки. То есть мы пишем this.state?.done, указывая, что мы обращаемся к свойству done объекта this.state, но надо проверить если ли этот объект. Подробнее читай здесь: https://learn.javascript.ru/optional-chaining
В твоем случае при с классическим синтаксисом пришлось бы писать так:
Или так:
Второй вариант не подгрузился. Я даже не знал, что есть такое - Опциональная цепочка '?.' думал странный, какой-то тернарник)
В первом варианте убрал скобки, со скобками не работает:
Получилось так:
Мне кажется самая понятная конструкция получилась.
Через опциональную цепочку пока не догоняю почему он работает. А в третьем варианте слишком сложная конструкция получается логическое И плюс тернарник. В моем же варианте получается возьми или это или другое , другое или это. Правильно вообще написал и понимаю эту конструкцию?)
Нет, в первом варианте не в скобках дело, а в раскладке (на цифре 7 висят и & и ?). То есть должно быть не done: !(this.state ?? this.state.done), done: !(this.state && this.state.done)
>> Мне кажется самая понятная конструкция получилась.
Это самая неправильная конструкция :)
Точнее, она будет работать, но:
1. Если не будет объекта this.state, то будет ошибка (вспоминаем про ?.).
2. ?? this.state.done здесь вероятнее всего не имеет никакого смысла, то есть можно безболезненно удалить.
>> В моем же варианте получается возьми или это или другое , другое или это.
Твой вариант - это усложненный мой
К тому же, как я и сказал, если не будет объекта this.state, то будет ошибка. А это совсем не исключено, не всегда классовые компоненты объявляют с инициализацией стейта.
2. ?? this.state.done здесь вероятнее всего не имеет никакого смысла, то есть можно безболезненно удалить.
Да без него тоже работает.
done: !this.state?.done
Смысл работы этой конструкции вообще не понимаю, как и почему она работает(
И вообще теперь не понимаю почему и эта конструкция работает done: !this.state.done вроде нет никаких условий и все работает прям магия:)
Рука-лицо... Учи матчасть внимательней. Я зачем уроки сюда с FreeCodeCamp импортировал?
Устанавливаем новое значение. Восклицательный знак в начале - это отрицание Не. То есть если this.state?.done === true, то Не будет false. Иначе (то есть false, null, undefined, 0, '' и т.п.) будет приведено к логическому true.
?. здесь примеряется для предотвращения ошибки на случай если объект this.state отсутствует.
Устанавливаем значение в стейт.
А наш вариант
это просто сокращенная форма без использования дополнительной переменной newValue.
Продолжаем .... дальше .
Восклицательный знак в начале - это отрицание Не. - Здесь понятно.
То есть если this.state?.done === true, то Не будет false. - Если подразумевается, что ты говорил про восклицательный знак в предыдущем предложении, тогда получается !this.state?.done так как оно изначально было false значит он станет true.
Иначе (то есть false, null, undefined, 0, '' и т.п.) будет приведено к логическому true. (?. здесь примеряется для предотвращения ошибки на случай если объект this.state отсутствует. )
Здесь тоже понятно, что опциональная цепочка ?. проверяет есть ли объект this.state, если его нет он все равно продолжит выполнение. И так как после .? идет done он возьмет текущее состояние стейта объявленое по умолчанию false. (Это предположение здесь уже не понимаю, что реально на самом деле происходит.) И здесь еще кстати появился вопрос, даже если опциональная цепочка ?. проверяет наличие this.state там же стоит восклицательный знак отрицания, тогда получается он опять должен вернуть true.
В итоге получается, что если кликаем, когда state находится в состояние false он отправляет true, если state находится в состоянии false он отправляет true. Только я не понимаю, как вообще обработчик понимает в каком сейчас состоянии находится state, я думал так, что обработчик просто устонавливает и отправляет новое сотояние state, через setState, а получается он его еще и каким-то образом сравнивает его с текущим state.
Или я вообще опять все неправильно понимаю?
Ты каким-то удивительным образом умеешь понимать и не понимать одновременно...
Если тебе не понятна конструкция !this.state?.done, то перепиши ее в !(this.state?.done). Может так тебе будет понятноей? Ты путаешься с моментом когда именно применяется восклицательный знак, так как он стоит перед this... Но правильно воспринимать не (!this)(.state)(.done), а именно !(this.state?.done), потому что восклицательный знак воздействует на значение конечного элемента, а не на первый элемент, то есть на done, а не на this.
Еще ты можешь сделать так, чтобы было понятней:
И можешь в консоли поиграться с такими конструкициями:
Приведение типов. Отрицание пустого дает истину.
Ты каким-то удивительным образом умеешь понимать и не понимать одновременно... :)
У тебя тоже есть классная супер способность, делать сложные вещи, еще сложней для понимания:) Вот только пока не понимаю ты - это специально делаешь или ты на таком небесном уровне, что для тебя - это кажется простым:)
Ладно сделаем вид, что я понял, как работает эта конструкция !(this.state?.done). так или иначе насколько я понимаю она в разных случаях меняет значение на true или false.
Но я не понимаю, как она его меняет она использует текущий state для замены, сравнивает в каком он сотоянии находится. Вот этот вопрос, на который ты не ответил:
В итоге получается, что если кликаем, когда state находится в состояние false он отправляет true, если state находится в состоянии false он отправляет true. Только я не понимаю, как вообще обработчик понимает в каком сейчас состоянии находится state, я думал так, что обработчик просто устонавливает и отправляет новое сотояние state, через setState, а получается он его еще и каким-то образом сравнивает его с текущим state.
Мне кажется здесь основной затык. Я не понимаю setState при замене объекта отслеживает текущее состояние state, чтобы выполнять эти операции !(this.state?.done) или done: !this.state.done, чтобы эти конструкции работали, если я правильно понимаю дожен быть какой-то тригер, не могут же они сами по себе меняться. Клик в даном случае запускает функцию setState, но сами значение что-то же должно менять, как они принимают или то или другое значение в объекте, которым мы меняем state?
>> не могут же они сами по себе меняться
Они сами по себе и не меняются. Ты же вызываешь setState(...). И никакого сравнения здесь нет, здесь есть получение текущего значения и установка нового инвертированного.