Программно свернуть все доступные для реагирования аккордеонные панели

#reactjs #accordion

#reactjs #аккордеон

Вопрос:

Я использую доступный для реагирования аккордеон, чтобы предоставлять пользователю форму по одной панели за раз. Существует кнопка «Сброс», которая сбрасывает воздействие любой из кнопок, которые пользователь мог нажать. Кнопки находятся внутри панелей. Как программно свернуть любые открытые панели? Для AccordionItem существует опция dangerouslySetExpanded, но я не вижу никаких практических примеров ее использования или подробной документации по этой опции (именно здесь эта опция описана в документах). Должен ли я использовать переменные состояния здесь для развернуто-свернутого состояния каждого элемента, чтобы иметь возможность программно управлять им? Вот упрощенная версия кода, который у меня есть сейчас:

 import React from 'react';
import ToggleButton from "react-bootstrap/ToggleButton";
import ButtonGroup from "react-bootstrap/ButtonGroup";
import 'bootstrap/dist/css/bootstrap.min.css';
import {Accordion, AccordionItem, AccordionItemHeading, AccordionItemButton, AccordionItemPanel} from 'react-accessible-accordion';


export const AccordionComponent = props => {
  stateHooks = [React.useState(-1), React.useState(-1)]
  const [ [varA, setVarA], [varB, setVarB] ] = stateHooks
  
  const handleResetAccordion = e => {
    e.preventDefault();
    stateHooks.forEach(hook => {  // pass -1 to each setter
      hook[1]('-1');  // index 1 contains the setter
    })
  }

  return (
    <div className="accordion_container">
      <Accordion allowZeroExpanded={true}>
        <AccordionItem>
          <AccordionItemHeading>
            <AccordionItemButton> Panel #1 Title </AccordionItemButton>
          </AccordionItemHeading>
          <AccordionItemPanel>
            <div className='radioQuestionCard'>
              <h3>Question #1 Prompt:</h3>
              <ButtonGroup className='radio' toggle id='q1'>
                <ToggleButton key='0' type="radio" name="q1" value='0' checked={varA === '0'}
                  onChange={e => setVarA(e.currentTarget.value)} > Q1: Option1
                </ToggleButton>
                <ToggleButton key='1' type="radio" name="q1" value='1' checked={varA === '1'}
                  onChange={e => setVarA(e.currentTarget.value)} > Q1: Option2
                </ToggleButton>
              </ButtonGroup>
            </div>
          </AccordionItemPanel>
        </AccordionItem>
        <AccordionItem>
          <AccordionItemHeading>
            <AccordionItemButton> Panel #2 Title </AccordionItemButton>
          </AccordionItemHeading>
          <AccordionItemPanel>
            <div className='radioQuestionCard'>
              <h3>Question #2 Prompt:</h3>
              <ButtonGroup className='radio' toggle id='q2'>
                <ToggleButton key='0' type="radio" name="q2" value='0' checked={varB === '0'}
                  onChange={e => setVarB(e.currentTarget.value)} > Q2: Option1
                </ToggleButton>
                <ToggleButton key='1' type="radio" name="q2" value='1' checked={varB === '1'}
                  onChange={e => setVarB(e.currentTarget.value)} > Q2: Option2
                </ToggleButton>
              </ButtonGroup>
            </div>
          </AccordionItemPanel>
        </AccordionItem>
      </Accordion>
      <button className='btn btn-danger btn-sm'
        onClick={handleResetAccordion} id='resetAccordion'> Reset
      </button>
    </div>
  )
}
 

Комментарии:

1. Похоже, вы уже делаете это с помощью функции сброса. Что вы подразумеваете под «программным свертыванием любых открытых панелей»? Когда вы хотите свернуть их все?

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

3. Вы пытались добавить dangerouslySetExpanded опору на AccordianItem s? Еще пара вещей — в документах говорится dangerouslySetExpanding , но это неправильно. И выше, вы проверяете наличие varA в пункте b, может быть просто опечаткой псевдокода. Глядя на код здесь — github.com/springload/react-accessible-accordion/tree/master / … — вы можете увидеть, как используется реквизит.

4. Нижний пример здесь — react-accessible-accordion.springload.co.nz

5. @MarkSwardstrom Я ссылался на этот пример в своем первоначальном вопросе, но это ручное назначение, а не программное. Другими словами, вы можете принудительно открыть определенные панели с самого начала, но это не является динамическим, и пользователь больше не может управлять accordion. Флаг dangerouslySetExpanded имеет чрезвычайно узкий вариант использования.

Ответ №1:

В react-accordion намеренно отсутствует возможность программного управления расширенным состоянием панелей аккордеона, поэтому я нашел обходной путь — поместить весь аккордеон внутри div и присвоить этому div ключевой параметр. При изменении ключа аккордеон будет принудительно инициализирован.

 let accordion_key = 12345;

const handleReinitialize = () => accordion_key  ;

return(
  <div className="accordion_container" key={accordion_key}>
    <Accordion>
      <AccordionItem>
        <AccordionItemHeading>
        ... etc.
    <button onClick={handleReinitialize} id='reinitialize'>Reinitialize Accordion</button>
  </div>
)
 

Комментарии:

1. При повторном запуске я теряю свое текущее состояние при использовании этого для технологии FORM. Другими словами, будьте осторожны с вашим вариантом использования при использовании этого метода, иначе {дочерние элементы}, содержащиеся в AccordionItem, будут повторно инициализированы…

2. Этот метод работает, но нет необходимости оборачивать accordion внутри div. Kay может быть установлен для аккордеона напрямую.

3. В этом случае div необходим, потому что React требует, чтобы вы возвращали один элемент, поэтому у вас не может быть аккордеона и кнопки в качестве двух свободных элементов. Но вы правы, что вместо этого ключ может просто перейти непосредственно на аккордеон.

4. Вы можете использовать <React.Fragment> , если хотите избежать дополнительного div

Ответ №2:

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

 <AccordionItem dangerouslySetExpanded={isExpanded}> 
...
</AccordionItem>
 

где-то isExpanded задается переменной setState

 const [ isExpanded, setIsExpanded ] = setState()
 
 const closeAll = () => {
  setIsExpanded(false)
}
 

Комментарии:

1. Это закрывает все AccordionItems, но пользователь больше не может взаимодействовать с ними, поэтому пользователь не может открыть их снова, если false . Если установлено значение false, а затем undefined, состояние кнопки снова откроет все, что было закрыто.

Ответ №3:

Для более старой версии вы можете попробовать использовать расширенный раскрывающийся список react accessible, а затем добавить и onclick к элементу div в AccordionItemTitle .

 <AccordionItem uuid="a" expanded={()=>this.setIsCollapse("a")}>
<AccordionItemTitle> 
 <div onClick={(value)=>this.onChangeAccordion(value)}>
 </div>   
</AccordionItemTitle>  
</AccordionItem>