Есть классовый компонент, который при клике переворачивает карточку и добавляет стиль. Мне нужно сделать так, чтобы после того как он открыл эту карточку, при клике опять по этой карточке он ее закрыл. Грубо говоря сбросил состояние к обычному 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, то будет ошибка. А это совсем не исключено, не всегда классовые компоненты объявляют с инициализацией стейта.
Рука-лицо... Учи матчасть внимательней. Я зачем уроки сюда с 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(...). И никакого сравнения здесь нет, здесь есть получение текущего значения и установка нового инвертированного. В общем, ты не понимаешь как работают стейты в реакте. Иди уроки проходи начиная с этого.