Каким образом каждый <li>в <ul>может изменить свое имя класса, не затрагивая других? - PullRequest
5 голосов
/ 29 марта 2020

Здесь будет необычное количество кода, потому что я пытаюсь поделиться всем, что происходит.

Что я пытаюсь сделать, это ... В списке:

  1. Пометить службы как завершенные.
  2. Изменение их цвета и скрытие после завершения.
  3. Отображение скрытых служб при нажатии кнопки.

Мне удалось скрыть каждую отдельную службу, но не смог работать с кнопкой, которая скрывает / показывает все завершенные услуги.

У меня есть поставщик контекста:

const ContextBooking = React.createContext()

const ContextProviderBooking = ({ children }) => {
  const [isHidden, setIsHidden] = useState(false); //sharing among both components to hide/show list

  return <ContextBooking.Provider value={{ isHidden, setIsHidden }}>
    {children}
  </ContextBooking.Provider>
}
export { ContextBooking, ContextProviderBooking }

, который передается через компонент BookingsDisplay в другом файле

...
<ContextProviderBooking>
      <BookingsDisplay /> //this encapsulates each <Booking />
</ContextProviderBooking>
...

Я предоставляю каждую из служб в более крупном компоненте под названием «BookingsDisplay»

const BookingsDisplay = () => {
  const { isHidden, setIsHidden } = useContext(ContextBooking)  
  const display = day => //function that displays each service according to the day it was booked for
    allBookings.map( //allBookings is a json file
      item =>
        item.day === day && ( 
          <Booking
            isHidden={isHidden}
            completed={item.completed} //comes from json file, all default to false
            key={item.id}
            id={item.id}
            time={item.time}
            name={item.name}
            date={item.date} 
          />
        )
    )
  return (
    <div className="bookings">
      <h2 className="ib">Next bookings</h2>
      <button //This won't work as expected and hide/show all of the 'completed' bookings
          onClick={() =>{ 
            setIsHidden(!isHidden);}
      }>
          Show hidden  
      </button>
      <h2>Today</h2>      
      <ul> {display('today')} </ul>
      <h2> Tomorrow </h2>
      <ul> {display('tomorrow')} </ul>
      <h2> General </h2>
      <ul> {display('other')} </ul>
    </div>
  )
}

Каждый компонент «Бронирование» имеет кнопку, которая помечает службу как завершенную. Это происходит путем условного изменения класса каждого компонента. Это прекрасно работает, насколько я понимаю

const Booking = (props) => {
  const [isHidden, setIsHidden] = useState(props.isHidden)
  console.log(props.isHidden) // will output true or false 16 times(there are 16 component in total)
  const [isCompleted, setIsCompleted] = useState(props.completed);
  return (
    <li
      className={
        isCompleted && isHidden ? 'booking-complete hide' //class names are not changing individually
        : isCompleted ? 'booking-complete'                //if button is pressed on one of them,
        : 'booking'                                       //it may affect the other
      }
      key={props.id}
      id={props.id}>
      <h3>{props.date}</h3>
      <h4>{props.time}</h4>
      <h5>{props.name}</h5>
      <button
        onClick={() => { //shouldn't this button work of each li and not sometimes all of them?
          if (!isCompleted && !isHidden) { 
            setIsCompleted(!isCompleted); //this changes color of the service as className changes
            setTimeout(() => setIsHidden(!isHidden), 200) //after a short time it is hidden
          }
          else if (isCompleted && !isHidden) {
            setIsCompleted(!isCompleted);
          }
          else {
            setIsCompleted(!isCompleted);
            setIsHidden(!isHidden);
          }
        }}>
        {!isCompleted ? `Completed` : `Not complete`}
      </button>
    </li>
  )
}

1 Ответ

6 голосов
/ 02 апреля 2020

В вашем приложении есть два вида isHidden. Меня называют в контексте глобальный скрытый isAllHidden, а тот в <Booking /> локальный скрытый isHidden.

Проблема в том, что вы неправильно использовать два. local hidden является внутренним состоянием <Booking />. Причина его существования в том, что вам нужна задержка анимации 200 мс, в противном случае ее можно заменить на isCompleted Таким образом, он должен быть получен из isCompleted вместо isAllHidden.

Fix 1:

const Booking = (props) => {
  const [isHidden, setIsHidden] = useState(props.completed)
}

Now global hidden и local hidden объединить, чтобы решить, следует ли скрывать бронирование. Ваша логика c должна отражать этот факт.

Fix 2:

  const shouldBeHidden = Boolean(props.isAllHidden && isHidden)

  return (
    <li
      className={
        isCompleted && shouldBeHidden ? 'booking-complete hide' 
        : isCompleted ? 'booking-complete'on one of them,
        : 'booking'other
      }
    >
  ...

Составить:

const Booking = (props) => {
  const [isHidden, setIsHidden] = useState(props.completed)
  const [isCompleted, setIsCompleted] = useState(props.completed)

  const shouldBeHidden = props.isAllHidden && isHidden

  return (
    <li
      className={
        isCompleted && shouldBeHidden ? 'booking-complete hide' //class names are not changing individually
        : isCompleted ? 'booking-complete'                //if button is pressed on one of them,
        : 'booking'                                       //it may affect the other
      }
    >
      <input type='checkbox' checked={isCompleted} onChange={() => {
        setIsCompleted(!isCompleted)
        setTimeout(() => setIsHidden(!isHidden), 200)
      }}/>
      <span>{props.name}</span>
    </li>
  )
}

Я установил demoboard здесь, чтобы показать результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...