Условно применяя класс, который изменяется по клику - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть компонент реагирования. Я тоже пытаюсь установить «активный» класс. Вот мой код, который я использую, чтобы проверить, должен ли быть установлен активный класс.

  {sku.colors &&
  (<div className="swatches" styleName="swatches">
      <span className="color" styleName="color" data-name="color">
    {sku.colors.map((option, index) => {   
      return(
        <span className={this.state.selectedColor === option.name ? 'active': ''} styleName="swatch" onClick={this.onColorChange.bind(this, option.name)} style={{backgroundImage: 'url(' + swatchImg + ')' }} key={index}>{option.name}</span>
      )
    })}
    </span>
  </div>)                
}

У меня state.selectedColor определен как реквизит

constructor(props) {
super(props);

this.state = { selectedColor: 'Black' };
}

А вот моя функция onClick:

onColorChange(currentColor){
//add sizes for this color
this.state.selectedColor = currentColor;
}

Проблема заключается только в проверке, если selectedColor = option.name при первой загрузке компонента. Проверка не повторяется после запуска функции onClick, поэтому активный класс никогда не обновляется.

Я думаю, что мне может понадобиться перерисовать этот раздел после события onClick. У кого-нибудь есть какие-либо мнения / советы по решению этой проблемы?

РЕДАКТИРОВАТЬ: я вижу, что state.selectedColor корректно обновляется по событию click, но проверка активного класса не работает.

Я добавил:

console.log(this.state.selectedColor);

и корректно обновляется при нажатии.

Ответы [ 4 ]

0 голосов
/ 13 сентября 2018

Вы уверены, что все делаете правильно?Здесь работает:

const sku = {
  colors: [
    { id: 1, name: "Black" },
    { id: 2, name: "Red" },
    { id: 3, name: "White" },
  ],
};

class App extends React.Component {
  state = {
    selectedColor: "Red"
  };
  
  onColorChange ( currentColor ) {
    this.setState( { selectedColor: currentColor } );
  }

  render() {
    return (
      <div>
        {sku.colors && (
          <div className="swatches" styleName="swatches">
            <span className="color" styleName="color" data-name="color">
              {sku.colors.map((option, index) => (
                <span
                  className={
                    this.state.selectedColor === option.name ? "active" : ""
                  }
                  styleName="swatch"
                  onClick={this.onColorChange.bind(this, option.name)}
                  key={index}
                >
                  {option.name}
                </span>
              ))}
            </span>
          </div>
        )}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
.active {
  font-size: 20px;
  font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Кроме того, если вы извлекаете каждый option в его компонент, вам не нужно напрямую связывать свою функцию в JXS.Таким образом, он не будет создан в каждом рендере.Если вы используете его как это или с функцией стрелки, он будет создан при каждом рендере.Кроме того, если вы посмотрите на консоль, React предупредит вас об использовании атрибута styleName как stylename.

const sku = {
  colors: [
    { id: 1, name: "Black" },
    { id: 2, name: "Red" },
    { id: 3, name: "White" },
  ],
};

class App extends React.Component {
  state = {
    selectedColor: "Red",
  };

  onColorChange = currentColor =>
    this.setState( { selectedColor: currentColor } );

  render() {
    return (
      <div>
        {sku.colors && (
          <div className="swatches" styleName="swatches">
            <span className="color" styleName="color" data-name="color">
              {sku.colors.map( option => (
                <Option
                  key={option.id}
                  option={option}
                  selectedColor={this.state.selectedColor}
                  onColorChange={this.onColorChange}
                />
              ) )}
            </span>
          </div>
        )}
      </div>
    );
  }
}

const Option = ( props ) => {
  const { option, selectedColor, onColorChange } = props;
  const handleChange = () => onColorChange( option.name );

  return (
    <span
      className={
        selectedColor === option.name ? "active" : ""
      }
      styleName="swatch"
      onClick={handleChange}
    >
      {option.name}
    </span>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
.active {
  font-size: 20px;
  font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
0 голосов
/ 12 сентября 2018

Попробуйте таким образом:

onColorChange(currentColor){
//add sizes for this color
this.setState({selectedColor: currentColor});
}
0 голосов
/ 12 сентября 2018

Ваша интуиция верна, вам нужно сделать повторную визуализацию после изменения state.selectedColor.

Использование функции this.setState({selectedColor: currentColor}) обновит ваше состояние, а затем сразу же включит повторную визуализацию. Это инструмент, который предоставляет React, поскольку это такое обычное действие (то есть изменение состояния и повторная визуализация).

Следует иметь в виду, что использование setState внутри функции render может вызвать бесконечный цикл.

0 голосов
/ 12 сентября 2018

Вы должны использовать this.setState({ selectedColor: currentColor }) вместо this.state.selectedColor = currentColor.Никогда не пытайтесь обновить свои свойства состояния, назначая им значения напрямую.Вероятно, именно поэтому повторное рендеринг также не запускается.

Это также указано в React Docs: состояние

...