Bilbo Baggins
Bilbo Baggins

Reputation: 3019

Facing issues with passing parameters to method in reactjs

I am creating a demo application from the course. I have defined my component in following way.

const Book = (props) => {
  console.log(">>>>>>>>>>>");
  console.log(props.onAnswerSelected);
  return (
    <div className="answer" onClick={props.onAnswerSelected}>
      <h4>{props.title}</h4>
    </div>
  )
}

This component renders the book name. On clicking the book name it should pass the book title to the method onAnswerSelected. Book is composed inside another component Turn.

export default class Turn extends Component {

  render() {

    console.log("Turn props >>> ", this.props);
    return (
      <div className="row turn" style={{backgroundColor: this.highlightTheBackgroundColor(this.props.highlightmapping)}}>
        <div className="col-4 offset-1">
            <img src={this.props.author.imageUrl} className="authorimage" alt="Author"></img>
        </div>
        <div className="col-6">
          {this.props.books.map((title) => <Book title={title} key={title} onAnswerSelected={this.props.onAnswerSelected}></Book>)}
        </div>
      </div>
    )
  }

  highlightTheBackgroundColor(highlightmapping) {
    if(!highlightmapping) {
      highlightmapping = 'none';
    }
    let colors = {
      'none' : "none", 
      'correct' : "green",
      'wrong' : "orange"
    }
    console.log("Input mapping .>>> ", highlightmapping);
    console.log("Required highlight color >> ", colors[highlightmapping]);
    return colors[highlightmapping];
  }
}

This is used inside another component called AuthorQuiz.

    class AuthorQuiz extends Component {
      render() {
        console.log("TURN DATA FOUND >>> ", this.props.turnData);

        return (
          <div className="container-fluid">

            <Hero />
            <Turn {...this.props.turnData} highlightmapping={this.props.highlightmapping} onAnswerSelected={this.props.onAnswerSelected}/>
            <Continue /> 
            <Footer />

            <PreventDefaultComponent />

            {/* <Button label="Click me!"/>
            <ButtonExntended label="Click Another"/>
            <ClickCounterComponentWithState></ClickCounterComponentWithState> */}
          </div>
        );
      }
    }

The function is defined in index.js file which is as follows:


const state = {
    turnData:  getTurnData(Authors),
    allBooks: getAllBooks(Authors),
    highlight: 'none'
}

function getAllBooks(Authors) {
    const allBooks = Authors.reduce(function (p,c, i) {
        return p.concat(c.books);
    }, []);
    return allBooks;
}

function getTurnData(Authors) {
    let allBooks = getAllBooks(Authors);
    console.log("all Books >>>> ", allBooks);
    const fourRandomBooks = shuffle(allBooks).slice(0,4);
    const answer = sample(fourRandomBooks);

    return {books: fourRandomBooks,
        author: Authors.find((author) => author.books.some((title) => title === answer))
    };
}

function onAnswerSelected(event, answer) {
    console.log("On Answer Selected called ... ", answer);
    console.log("Logging the event >>> ", event.target.text);
    const isCorrect = state.allBooks.some((book) => {
        return book === answer;
    });
    state.highlight = isCorrect? "correct" : "wrong";
    // render();
}

// function render() {
    ReactDOM.render(<AuthorQuiz {...state} onAnswerSelected={onAnswerSelected}/>, document.getElementById('root'));
// }

// render();

serviceWorker.unregister();

for the sake of shortening the question I have omitted the imports. All I get is in the method is event only, I can't find the answer in it.

I am not sure what I am doing wrong. If someone can help. Thanks.

P.S I have refered to other questions from there I got the idea of passing an event but when I do event.target.dataset/text/value I get undefined, I think there has to be a react way or better way to pass the value in it.

Update : 1 This part doesn't work, I get entire h4 or div (depending on where I click in the console). further more when I try to pass the value it still doesn't give out the value in the function, all i get is events inside the function.

the output of on click is as follows:

index.js:35 On Answer Selected called ...  <h4>​Roughing it​</h4>​
index.js:35 On Answer Selected called ...  <div class=​"answer" title=​"Roughing it" value=​"Roughing it">​…​</div>​<h4>​Roughing it​</h4>​</div>​

Upvotes: 1

Views: 88

Answers (2)

Fawzi
Fawzi

Reputation: 369

Try calling the function with the data you need in the parents.

{()=>{ props.onAnswerSelected(props.title//or id)}}

if you don't want to use the inline function try this

class Book extends Component {
  handleClick = () => {
    this.props.onAnswerSelected(this.props.title);
  }

  render() {
    return (
      <div className="answer" onClick={this.handleClick}>
      <h4>{props.title}</h4>
    </div>
    );
  }
}

this will then re-render only when the props change (because the handler reference now never changes):

Upvotes: 1

Shubham Khatri
Shubham Khatri

Reputation: 281892

Nowhere in your example, you have passed the book title to the onAnswerSelected function. You can pass it from the Books component like

const Book = (props) => {
  console.log(">>>>>>>>>>>");
  console.log(props.onAnswerSelected);
  return (
    <div className="answer" onClick={(e) => props.onAnswerSelected(e, props.title)}>
      <h4>{props.title}</h4>
    </div>
  )
}

and using it in onAnswerSelected method from answer argument value

Also the reason that event.target.text/dataset/value return undefined is because you haven't set those attributes on the div element in Book and also because they aren't the defined attributes on div and hence you need to access them using getAttribute once you define them and using it from the currentTarget since it has the handler defined.

Another possible solution is

const Book = (props) => {
  console.log(">>>>>>>>>>>");
  console.log(props.onAnswerSelected);
  return (
    <div className="answer" text={props.title} onClick={props.onAnswerSelected}>
      <h4>{props.title}</h4>
    </div>
  )
}

function onAnswerSelected(event) {
    console.log("On Answer Selected called ... ", answer);
    console.log("Logging the event >>> ", event.currentTarget.getAttribute('text'));
    const answer = event.currentTarget.getAttribute('text')
    const isCorrect = state.allBooks.some((book) => {
        return book === answer;
    });
    state.highlight = isCorrect? "correct" : "wrong";
    // render();
}

Upvotes: 1

Related Questions