Показать или скрыть определенный элемент в реакции

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

class Faqs extends Component {
  constructor(props){
    super(props);
    this.state = {
      isHidden: true
    }
  }
  toggleHidden () {
    this.setState({
      isHidden: !this.state.isHidden
    })
  }
render() {
        return (
            <div>
               <span onClick={() => this.toggleHidden()}><strong>This is the question</strong></span>
               {!this.state.isHidden && <p>Answer for the question</p>} <br/>

               <span onClick={() => this.toggleHidden()}><strong>Question2</strong></span>
               {!this.state.isHidden && <p>Answer2</p>} <br/>
               <hr></hr>            
            </div >
        )
    }
}

Возможный дубликат Показать или скрыть элемент в React

Jonathan 26.01.2019 13:44
4
1
14 736
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Я бы написал другой обработчик ответа. В будущем, если вам понадобится больше логики, ответ будет масштабируемым. Уведомление renderAnswer

class Faqs extends Component {
  constructor(props){
    super(props);
    this.state = {
      isHidden: true
    }
  }
  toggleHidden () {
    this.setState({
      isHidden: !this.state.isHidden
    })
  }
  renderAnswer() {
    if (this.state.isHidden) {
      return;
    }
    return (
      <p>Answer</p>
    );
  }
  render() {
    return (
            <div>
               <span onClick={() => this.toggleHidden()}><strong>This is the question</strong></span>
               { this.renderAnswer() } <br/>

               <span onClick={() => this.toggleHidden()}><strong>Question2</strong></span>
               { this.renderAnswer() } <br/>
               <hr></hr>            
            </div >
        )
    }
}

Это еще один способ делать то, что вы хотите. (Это позволит открывать только по одному за раз)

class Faqs extends Component {
  constructor(props){
    super(props);
    this.state = {
      hiddenId: null,
    }
  }
  setHiddenId(id) {
    this.setState({
      hiddenId: id
    })
  }
  render() {
        return (
            <div>
               <span onClick={() => this.setHiddenId('one')}><strong>This is the question</strong></span>
               {this.state.hiddenId === 'one' && <p>Answer for the question</p>} <br/>

           <span onClick={() => this.setHiddenId('two')}><strong>Question2</strong></span>
           {this.state.hiddenId === 'two' && <p>Answer2</p>} <br/>
           <hr></hr>            
        </div >
    )
    }
}
Ответ принят как подходящий

Вы можете разбить свой компонент на еще один уровень, чтобы иметь подкомпонент, который отображает только вопрос и соответствующий ответ. Передайте вопрос и ответы в качестве реквизита. Таким образом, вы можете использовать один и тот же компонент для всех вопросов, и при этом каждая пара вопрос / ответ будет иметь собственное состояние.

class Faq extends Component{
 state = {isHidden: true}
 toggleHidden = ()=>this.setState((prevState)=>({isHidden: !prevState.isHidden}))
 render(){
  return(
     <div>
     <span onClick={this.toggleHidden}>
           <strong>{props.question}</strong></span>
           {!this.state.isHidden && <p>{props.answer}</p>}   
     </div>
  )
 }
}




class Faqs extends Component {

render() {
        return (
            <div>
              <Faq question={"Question 1"} answer={"answer 1"} />
              <Faq question={"Question 2"} answer={"answer 2"} />
            </div >
        )
    }
}

Проблема в том, что вы используете логическую часть состояния один для управления логикой нескольких частей. Это классический сценарий использования отдельных компонентов.

Создайте новый компонент ToggleQuestion, который инкапсулирует механизм шоу / раскрытия.

Компонент Faqs вместо этого управляет списком компонентов ToggleQuestion.

const QUESTIONS = [
  { title: 'q1', answer: 'a1' },
  { title: 'q2', answer: 'a2' }
]

class ToggleQuestion extends React.Component {
  constructor (props) {
    super(props)
    this.state = { isHidden: true }
  }
  
  toggleHidden () {
    this.setState({ isHidden: !this.state.isHidden })
  }
  
  render () {
    const { question, answer } = this.props
    const { isHidden } = this.state
    return (
      <div>
        <span>{question}</span>
        { !isHidden && <span>{answer}</span> }
        <button onClick={this.toggleHidden.bind(this)}>
          Reveal Answer
        </button>
      </div>
    )
  }
}

class Faqs extends React.Component {
  render () {
    return (
      <div>
        { QUESTIONS.map(question => (
          <ToggleQuestion
            question={question.title}
            answer={question.answer}
          />
        ))}
      </div>
    )
  }
}

ReactDOM.render(<Faqs />, document.getElementById('container'))
<div id='container'></div>
<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>

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

редактировать. В наши дни и возраст уместно только показать пример с помощью хуков:

const {useState} = React;

const FaqApp = () => {
  const [ selectedQuestion, toggleQuestion ] = useState(-1);
  
  function openQuestion(index) {
    toggleQuestion(selectedQuestion === index ? -1 : index);
  }

  const faqs = getFaqs();

  return (
    <div>
      <h2>FAQs:</h2>
        {faqs.map(( { question, answer}, index) => (
          <div key={`item-${index}`} className={`item ${selectedQuestion === index ? 'open' : ''}`}>
            <p className='question' onClick={() => openQuestion(index)}>{question}</p>
            <p className='answer'>{answer}</p>
          </div>
        ))}
    </div>
  )
}

function getFaqs() {
  const faqs = [
    {
      question: 'Question 1',
      answer: 'answer 1'
    },
    {
      question: 'Question 2',
      answer: 'answer 2'
    }
  ];
  return faqs;
}


ReactDOM.render(
  <FaqApp />,
  document.getElementById("react")
);
body {
  background: #fff;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

h2 {
   margin-bottom: 11px;
}

.item + .item {
  margin-top: 11px;
}

.question {
  font-weight: bold;
  cursor: pointer;
}

.answer {
   display: none;
}

.open .answer {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

старая версия этого поста:

Я написал небольшой пример, который позволяет задать несколько вопросов:

class FaqApp extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      // start the page with all questions closed
    	selectedQuestion: -1
    };
    this.openQuestion = this.openQuestion.bind(this);
  }
	
  getFaqs() {
  	// some service returning a list of FAQs
  	const faqs = [
      {
        question: 'Question 1',
        answer: 'answer 1'
      },
      {
        question: 'Question 2',
        answer: 'answer 2'
      }
    ];
    return faqs;
  }
  
  openQuestion(index) {
    // when a question is opened, compare what was clicked and if we got a match, change state to show the desired question.
  	this.setState({
    	selectedQuestion: (this.state.selectedQuestion === index ? -1 : index)
    });
  }
  
  render() {
    // get a list of FAQs
    const faqs = this.getFaqs();
    return (
      <div>
        <h2>FAQs:</h2>
          {faqs.length && faqs.map((item, index) => (
            <div key={`item-${index}`} className={`item ${this.state.selectedQuestion === index ? 'open' : ''}`}>
                <p className='question' onClick={() => this.openQuestion(index)}>
                  {item.question}
                </p>
                <p className='answer'>
                  {item.answer}
                </p>
            </div>
          ))}
      </div>
    )
  }
}

ReactDOM.render(<FaqApp />, document.querySelector("#app"))
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

h2 {
   margin-bottom: 11px;
}

.item + .item {
  margin-top: 11px;
}

.question {
  font-weight: bold;
  cursor: pointer;
}

.answer {
   display: none;
}

.open .answer {
  display: block;
}
<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="app"></div>

ИМО, это более подходящий способ решения ReactJS.

vivekkupadhyay 12.12.2019 07:29

Другие вопросы по теме