在反应中显示或隐藏特定元素

Show or Hide a particular element in react

我必须显示常见问题解答列表并且我需要隐藏问题的答案。当我单击问题时,需要显示该特定问题的答案。我的问题是,我有一堆问题,当我点击按钮时,它会显示所有答案,而不是该问题的具体答案。

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 >
        )
    }
}

我会为答案编写不同的处理程序。将来如果您需要更多逻辑,答案将是可扩展的。注意 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 >
    )
    }
}

您可以将您的组件分解到更多级别,以获得一个仅呈现问题和相应答案的子组件。将问题和答案作为道具传递。通过这种方式,您可以对所有问题使用相同的组件,但每个 question/answer 对都会有自己的状态。

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 >
        )
    }
}

问题是您正在使用 one 布尔状态块来控制多个块的逻辑。这是使用单独组件的经典场景。

创建一个封装 show/reveal 机制的新组件 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>


这个post的旧版本:

我写了一个简单的例子,可以让你有多个问题:

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>