React Native TouchableOpacity не обновляет стили

У меня странная проблема с компонентом TouchableOpacity. У меня есть MainButton компонент, который принимает 2 реквизита, item и disabled. Основываясь на опоре disabled, я хочу, чтобы мой компонент MainButton применил другой стиль. Проблема в том, что когда компонент TouchableOpacity повторно визуализирует, он не обновляет стиль. Опора disabled правильно установлена ​​при повторном рендеринге.

Что делает это странным, так это то, что если я поменяю его на TouchableHeighlight, он будет работать, как ожидалось.

Кто-нибудь знает почему? Это ошибка в TouchableOpacity?

import React, { Component } from 'react'
import UI from '../styles/ui'

import {
  Text,
  TouchableOpacity
} from 'react-native'

const ui = new UI()
const styles = ui.styles

class MainButton extends Component {
  constructor (props) {
    super(props)
    this.state = {
      disabled : props.disabled,
      item: props.item
    }
  }

  componentWillReceiveProps(props) {
    this.setState({disabled:props.disabled})
  }

  render() {
    var normalStyles = [styles.mainButton,styles.widthEighty]
    var disabledStyle = [styles.mainButton,styles.widthEighty,styles.lowOpacity]
    var correctStyles = this.state.disabled ? disabledStyle : normalStyles
    console.log(this.state.disabled,'this.state.disabled ? ');
    return (
      <TouchableOpacity disabled={this.state.disabled} style={correctStyles} accessibilityLabel={this.state.item.name} onPress={this.state.item.onPress.bind(this)}>
        <Text style={styles.mediumLabel}>{this.state.item.name}</Text>
      </TouchableOpacity>
    );
  }
}

export { MainButton as default }

person Zolve    schedule 28.08.2017    source источник
comment
Вы когда-нибудь разбирались в этом? Интересно, имеет ли это какое-то отношение к TouchableOpacity , который оборачивает его дочерние элементы в Animated.View? Анимация не заканчивается вовремя или что-то в этом роде? В документации не упоминается, что TouchableHighlight выполняет аналогичную упаковку, но не копается в источнике для проверки! В любом случае, спасибо за подсказку TouchableHighlight!   -  person safarmstrong    schedule 10.10.2017
comment
У меня была такая же проблема, спасибо за подсказку, она сработала   -  person evanjmg    schedule 17.11.2017
comment
Вы нашли решение?   -  person rendom    schedule 01.04.2018


Ответы (4)


Во-первых, я не думаю, что пропсы disabled и item передаются в состояние. Вы можете сделать это напрямую и избавиться от конструктора и componentWillReceiveProps. componentWillReceiveProps метод жизненного цикла скоро будет устаревшим, поэтому они не поощряют его использование.

Также, если возможно, отделите обработчик событий от item props. Это не лучший способ сделать это

render () {
  const { disabled, item, onPress } = this.props;
  const { name } = item;
  ...
  return (
    ...
    <TouchableOpacity
      disabled={disabled}
      style={disabled ? disabledStyle : normalStyle}
      accessibilityLabel={name}
      onPress={onPress}
    >
      <Text style={styles.mediumLabel}>{name}</Text>
    </TouchableOpacity>
    ...
  ); 
}
person Daniel Zheng    schedule 21.08.2019

Обходной путь, который я придумал, - использовать

setOpacityTo(value), чтобы обновить холст.

Я сделал это componentDidUpdate(), поскольку этот метод жизненного цикла вызывается всякий раз, когда ваш новый стиль применяется к вашему компоненту. Поэтому я присвоил <TouchableOpacity/> компоненту ref и обновлял его всякий раз, когда его стиль менялся.

Пример:

import React, { Component } from 'react'
import UI from '../styles/ui'

import {
  Text,
  TouchableOpacity
} from 'react-native'

const ui = new UI()
const styles = ui.styles

class MainButton extends Component {
  constructor (props) {
    super(props)
    this.state = {
      disabled : props.disabled,
      item: props.item
    }
  }

  componentWillReceiveProps(props) {
    this.setState({disabled:props.disabled})
  }

  componentDidUpdate() {
    this.refs['touchable'].setOpacityTo(1.0);
  }

  render() {
    var normalStyles = [styles.mainButton,styles.widthEighty]
    var disabledStyle = [styles.mainButton,styles.widthEighty,styles.lowOpacity]
    var correctStyles = this.state.disabled ? disabledStyle : normalStyles
    console.log(this.state.disabled,'this.state.disabled ? ');
    return (
      <TouchableOpacity ref={'touchable'} disabled={this.state.disabled} style={correctStyles} accessibilityLabel={this.state.item.name} onPress={this.state.item.onPress.bind(this)}>
        <Text style={styles.mediumLabel}>{this.state.item.name}</Text>
      </TouchableOpacity>
    );
  }
}

export { MainButton as default }
person YoshiJaeger    schedule 06.09.2019

Если вы используете стиль opacity (который используется TouchableOpacity), вы должны установить этот стиль для дочерних элементов TouchableOpacity (например, View) следующим образом:

<TouchableOpacity
  disabled={disabled}
  accessibilityLabel={name}
  onPress={onPress}
>
  <View style={disabled ? disabledStyle : normalStyle}>
    <Text style={styles.mediumLabel}>{name}</Text>
  </View>
</TouchableOpacity>
person Robin Huy    schedule 14.10.2020

У меня недостаточно контекста, чтобы точно понять, чего вы здесь пытаетесь достичь, но попробуйте следующее:

  <TouchableOpacity disabled={this.state.disabled} style={this.state.disabled ? disabledStyle : normalStyles} accessibilityLabel={this.state.item.name} onPress={this.state.item.onPress.bind(this)}>
    <Text style={styles.mediumLabel}>{this.state.item.name}</Text>
  </TouchableOpacity>

Также недостаточно контекста о том, что делает 'this.state.item.onPress' или почему вы используете элемент, который вы передаете в реквизитах, чтобы изменить реквизиты в первую очередь. Похоже, вы можете улучшить то, как вы это реализовали, если вы дадите мне больше контекста, я смогу помочь.

person Yair Levi    schedule 20.06.2018