Обновление реквизитов функциональных компонентов не меняет стиль

У меня есть этот функциональный компонент для рендеринга диапазона в виде полосы. Когда я визуализирую компонент, я передаю свойство scrolled как false. Затем jQuery обновляет атрибут до true, когда я прокручиваю 150 пикселей. Я знаю, что использовать jQuery не рекомендуется, и я перехожу с него. На данный момент я хочу, чтобы это работало, поскольку я все еще изучаю функциональные компоненты.

export default function Button(props) {
  const [scrolled, setScrolled] = useState( props.scrolled );
  useEffect(() => {
    setScrolled(props.scrolled);
  }, [scrolled]);

  return (
    <HamburgerButton scrolled={scrolled}>
      <p>{scrolled}</p> 
      <span></span>
    </HamburgerButton>
  );
}

И это стилизованное определение компонента:

const HamburgerButton = styled.div`
  ...
  span {
        background: ${props => props.scrolled === 'false' ? props.theme.white : props.theme.black};
  }
  ...
`;

Когда я прокручиваю, я вижу, что атрибут scrolled в DOM изменился с «false» на «true», но интервалы остаются белыми. Кроме того, тег абзаца с {scrolled} не меняется с false.


person Casey    schedule 11.01.2020    source источник
comment
Вы выполняете строгую проверку равенства с ===, но сравниваете логическое значение со строкой, поэтому они никогда не будут равны. Должно быть просто props.scrolled === false   -  person Jayce444    schedule 11.01.2020
comment
@ Jayce444, реализующий это изменение, сохраняет элемент белым и не меняется при изменении атрибута scrolled. Похоже, что когда jQuery изменяет атрибут, он преобразует логическое значение в строку.   -  person Casey    schedule 11.01.2020
comment
@Кейси !props.scrolled || props.scrolled === 'false' ? props.theme.white : props.theme.black? Охватить оба сценария   -  person James    schedule 11.01.2020
comment
Я попробовал background: ${props => !props.scrolled || props.scrolled === false ? props.theme.white : props.theme.black};, но он по-прежнему не обновляет цвет, когда scrolled="true" применяется в качестве атрибута к компоненту.   -  person Casey    schedule 11.01.2020
comment
Какова цель реагирующих хуков? Кажется, вы можете просто передать props.scrolled прямо в HamburgerButton. Все, что вы сделали, это сохранили начальное значение props.scrolled в состоянии, обновили его тем же значением при первом вызове эффекта, и больше ничего не меняет значение scrolled для повторного запуска эффекта.   -  person Drew Reese    schedule 11.01.2020
comment
@DrewReese целью было изменить стиль компонента при прокрутке страницы - белая навигация, черная кнопка - черная навигация, белая кнопка. Проблема оказалась в том, что прокручиваемая опора никогда не менялась в родительском компоненте. Этот вопрос помог мне узнать, как работает useEffect, и я использовал его для изменения состояния кнопки при прокрутке страницы.   -  person Casey    schedule 12.01.2020


Ответы (1)


Проблема Ваш код запоминает значение props.scrolled в ловушках.

export default function Button(props) {
  const [scrolled, setScrolled] = useState( props.scrolled ); // state initialized
  useEffect(() => { // hook called first render
    setScrolled(props.scrolled); // state updated with same value
  }, [scrolled]); // state value never changes during life of component so effect hook never recomputes

  return (
    <HamburgerButton scrolled={scrolled}>
      <p>{scrolled}</p> 
      <span></span>
    </HamburgerButton>
  );
}

Решение. Вы можете напрямую передать свойство в HamburgerButton.

export default function Button(props) {
  return (
    <HamburgerButton scrolled={props.scrolled}>
      <p>{props.scrolled}</p> 
      <span></span>
    </HamburgerButton>
  );
}

Или используйте хуки и используйте правильную зависимость

export default function Button(props) {
  const [scrolled, setScrolled] = useState( props.scrolled );
  useEffect(() => {
    setScrolled(props.scrolled); // update state
  }, [props.scrolled]); // with the value that changes here

  return (
    <HamburgerButton scrolled={scrolled}>
      <p>{scrolled}</p> 
      <span></span>
    </HamburgerButton>
  );
}

Используйте положительное сравнение для истинной ветви тройки и используйте значения истинности/ложности javascript. Если scrolled равно true или любому другому истинному значению, сделать черным, если fasley, (false, 0, null, undefined) сделать белым.

const HamburgerButton = styled.div`
  ...
  span {
    background: ${props => props.scrolled ? props.theme.black : props.theme.white};
  }
  ...
`;

or

const HamburgerButton = styled.div`
  ...
  span {
    background: ${props => props.theme[props.scrolled ? 'black' : 'white']};
  }
  ...
`;
person Drew Reese    schedule 11.01.2020
comment
Привет! Большое спасибо за ваш подробный ответ. Я пробовал ваши решения и не играл в кости; Итак, я пошел и проверил состояние с помощью React Webtools. Я видел, что реквизиты не обновлялись для компонента! Оказывается, я не реализовал или забыл, как я реализовал изменение реквизита с помощью jQuery. Итак, я пошел и научился создавать прослушиватель событий для прокрутки и обновления состояния, когда пользователь прокручивал. Это с вашим решением сработало как шарм! Спасибо, что предоставили несколько вариантов реализации, очень подробно! - person Casey; 12.01.2020