Reputation: 3019
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
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
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