Можно ли стилизовать дочерний элемент флажка на основе состояния флажка без использования тернарности в стилизованных компонентах?

Я пытаюсь стилизовать этот компонент с помощью стилизованных компонентов, но мое решение кажется хакерским. Как лучше всего стилизовать этот компонент с помощью стилизованных компонентов?

Используя простой HTML и CSS, я могу создать это:

HTML:

<label>
  <input type="checkbox" value="s1"/>
  <div class="container">s1</div>
</label>
<label>
  <input type="checkbox" value="s2"/>
  <div class="container">s2</div>
</label>
<label>
  <input type="checkbox" value="s3"/>
  <div class="container">s3</div>
</label>
<label>
  <input type="checkbox" value="s4"/>
  <div class="container">s4</div>
</label>

CSS:

input[type=checkbox] {
  position: absolute;
  width: 0;    
}

.container {
  width: 5em;
  border: solid #aaa 1px;
  background: #fff
  color: #000;
}
.container:hover {
  background: #999;
}  

.container:active {
  background: #333;
  color:#fff
}

input[type=checkbox]:checked + .container {   
  background: #000;
  color: #fff;
}    

input[type=checkbox]:checked + .container:hover {
  background: #ddd;
}  

input[type=checkbox]:checked + .container:hover:active {
  background: white;
  color: black;
}  

Используя компонент React и стилизованные компоненты, я также могу создать его, но мне не нравится использовать два разных стилизованных компонента и тройной компонент для выполнения того, что я мог бы в CSS с помощью input[type=checkbox]:checked + .container.

import React, { useState } from 'react';
import styled from 'styled-components'

function Test() {
  const [selectedStations, setSelectedStations] = useState([]);  

  const Input = styled.input`
    position: absolute;
    width: 0;    
  ` 
  const UncheckedContainer = styled.div` 
    width: 5em;    
    border: solid #aaa 1px;
    background: #fff;
    color: #000;

  &:hover {
    background: #999;
  }  

  &:active {
      background: #333;
      color: #fff;
  }
  `
  const CheckedContainer = styled.div`
    width: 5em;
    border: solid black 1px;
    background: #000;
    color: #fff;

  &:hover {
    background: #ddd;
  }  

  &:active {
      background: #fff;
      color: #000;
  }  
  `

  function selectStations(e) {    
    let station = e.target.value;
    const s = [...selectedStations]
    const stationIndex = s.indexOf(station)

    if (stationIndex > -1) {
      s.splice(stationIndex, 1);
    } else {
      s.push(station);
      s.sort();
    }

    setSelectedStations(s)
  };


  return (
    <div>
        {new Array(4).fill('').map((v, i) =>{

          let checked = selectedStations.indexOf(`s${i+1}`) > -1         

          return(
            <label key={`station${i + 1}`}>
            <Input              
              type="checkbox"
              value={`s${i+1}`}
              checked={checked}
              onChange={(e)=>selectStations(e)}              
            />

            {checked ? 
              <CheckedContainer>
                  {`s${i+1}`}
              </CheckedContainer>            
            : 
              <UncheckedContainer>
                  {`Station ${i+1}`}
              </UncheckedContainer>
            }


          </label>
          )}
        )}
    </div>
  )
}

export default Test;

Можно ли немного очистить это, но по-прежнему использовать стилизованные компоненты?


person thebells1111    schedule 01.04.2019    source источник


Ответы (2)


Вы можете сохранить состояние флажка в переменной и передать его стилизованному компоненту, например:

<StyledComponent isChecked={isChecked} />

Затем в стилизованном компоненте:

const StyledComponent = styled.input`

 color: ${props => props.isChecked ? '#fff' : '#000'};

`

.. и так далее для цвета фона и границы.

person Nats    schedule 01.04.2019
comment
Вам все еще нужно использовать тернарный оператор (который я не считаю беспорядочным), но теперь у вас есть только один стилизованный компонент, а не два для проверенных / не проверенных. - person Nats; 01.04.2019
comment
Это ответило на мой вопрос. Он переместил тернар из функции рендеринга в функцию стилизованного компонента, что, как мне кажется, упрощает чтение кода. Это также уменьшило количество стилей, которые мне изначально приходилось делать, чтобы компонент работал. - person thebells1111; 01.04.2019

Вы можете получить доступ к реквизитам внутри styled-component, а также использовать sass, например вложенность, для нацеливания на детей.

const Checkbox = styled.label`
  postion: relative;
  input[type="checkbox"] {
    // style here
  }
  .inner-checkbox {
    color: ${props => props.checked ? "red" : "blue"};
    // style here
  }
`

const List = props => {
  return props.list.map(item => (
    <Checkbox key={item.id} checked={item.checked}>
      <input checked={item.checked} type="checkbox" onChange={this.updateState} />
      <div className="inner-checkbox" />
    </Checkbox>
  ))
}

Еще одна вещь, которую я бы категорически избегал, - это создание стилизованных компонентов внутри другого компонента.

person Patrick Krawczykowski    schedule 01.04.2019
comment
Я самоучка, не могли бы вы объяснить, почему вы советуете избегать стилизованных компонентов внутри другого компонента? - person thebells1111; 01.04.2019