简体   繁体   中英

React.js targeting a single element with a shared onClick function

I am new to both coding as well as React.js, so any assistance in learning what I am doing incorrectly is greatly appreciated! I am creating multiple cards on a page with riddles where the answer is hidden via css. I am using an onClick function ("toggleAnswer") to toggle the state of each answer to change the className so that the answer will either be visible or hidden. Currently, the onClick event is changing the state for all the answers. I realize this is because my code is not targeting a particular element, but I am unsure how this can be done. How can this be achieved? My code is currently like this:

// RiddlesPage where toggleAnswer function is defined
class RiddlesPage extends Component {
    constructor(props) {
        super(props);
        this.state = {
            questionData: [],
            isHidden: true
        };
        this.getPageData = this.getPageData.bind(this);
        this.toggleAnswer = this.toggleAnswer.bind(this);
    }
    getPageData() {
        console.log("we hit getPageData function starting --");
        helpers.getRiddlesPage().then(data => {
            console.log("this is the result", data);
            this.setState({
                questionData: data[0].questionData,
            });
        });
    }
    toggleAnswer(e) {
        this.setState({ isHidden: !this.state.isHidden });
    }
    componentWillMount() {
        this.getPageData();
    }
    render() {
        const answerClass = this.state.isHidden ? "answer-hide" : "answer";
        return (
            <div>
                <Riddles>
                    {this.state.questionData.map((data, index) => {
                        return (
                            <RiddlesItem
                                key={index}
                                id={index}
                                question={data.question}
                                answer={data.answer}
                                button={data.buttonURL}
                                answerClass={answerClass}
                                onClick={this.toggleAnswer}
                            />
                        );
                    })}
                </Riddles>
            </div>
        );
    }
}
export default RiddlesPage;

// Riddles Component
import React from "react";
import "./riddles.css";
const Riddles = props => (
    <div id="riddles-row">
        <div className="container">
            <div className="row">
                <div className="col-12">
                    <div>{props.children}</div>
                </div>
            </div>
        </div>
    </div>
);
export default Riddles;

// RiddlesItem Component where onClick function is set as a prop
import React from "react";
import "./riddles.css";
const RiddlesItem = props => (
  <div>
      <div className="card-body">
            <p id="question">{props.question}</p>    
            <img
              className="img-fluid"
              id={props.id}
              src={props.button}
              onClick={props.onClick}
              alt="answer button"
            />     
        <p className={props.answerClass}> {props.answer} </p>
      </div>
  </div>
);
export default RiddlesItem;

You'd have to keep track of each answer that has been shown in state (in an array or something).

First

Send the index of the answer up in the onclick function. In that function, check if it exists in the "shownAnswers" array and either add or remove it.

onClick={e => props.onClick(e, props.id)}

and

toggleAnswer(e, index) {
    if (this.state.shownAnswers.indexOf(index) > -1) {
        this.setState({
            shownAnswers: this.state.shownAnswers.filter(val => val !== index)
        });
    } else {
        this.setState({
            shownAnswers: this.state.shownAnswers.concat(index)
        });
    }
}

Then

When you're passing the class name down to the child component, check if its index is in the "shownAnswers" array to decide which class name to pass.

answerClass={this.state.shownAnswers.indexOf(index) > -1 ? "answer" : "answer-hide"}

Building off your example, it could look something like this (untested):

// RiddlesPage where toggleAnswer function is defined
class RiddlesPage extends Component {
    constructor(props) {
        super(props);
        this.state = {
            questionData: [],
            shownAnswers: []
        };
        this.getPageData = this.getPageData.bind(this);
        this.toggleAnswer = this.toggleAnswer.bind(this);
    }
    getPageData() {
        console.log("we hit getPageData function starting --");
        helpers.getRiddlesPage().then(data => {
            console.log("this is the result", data);
            this.setState({
                questionData: data[0].questionData,
            });
        });
    }
    toggleAnswer(e, index) {
        if (this.state.shownAnswers.indexOf(index) > -1) {
            this.setState({ shownAnswers: this.state.shownAnswers.filter(val => val !== index) });
        } else {
            this.setState({ shownAnswers: this.state.shownAnswers.concat(index) });
        }
    }
    componentWillMount() {
        this.getPageData();
    }
    render() {
        return (
            <div>
                <Riddles>
                    {this.state.questionData.map((data, index) => {
                        return (
                            <RiddlesItem
                                key={index}
                                id={index}
                                question={data.question}
                                answer={data.answer}
                                button={data.buttonURL}
                                answerClass={this.state.shownAnswers.indexOf(index) > -1 ? "answer" : "answer-hide"}
                                onClick={this.toggleAnswer}
                            />
                        );
                    })}
                </Riddles>
            </div>
        );
    }
}
export default RiddlesPage;

// Riddles Component
import React from "react";
import "./riddles.css";
const Riddles = props => (
    <div id="riddles-row">
        <div className="container">
            <div className="row">
                <div className="col-12">
                    <div>{props.children}</div>
                </div>
            </div>
        </div>
    </div>
);
export default Riddles;

// RiddlesItem Component where onClick function is set as a prop
import React from "react";
import "./riddles.css";
const RiddlesItem = props => (
  <div>
      <div className="card-body">
            <p id="question">{props.question}</p>    
            <img
              className="img-fluid"
              id={props.id}
              src={props.button}
              onClick={e => props.onClick(e, props.id)}
              alt="answer button"
            />     
        <p className={props.answerClass}> {props.answer} </p>
      </div>
  </div>
);
export default RiddlesItem;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM