Reputation: 13
just a bit of background, I am really new to javascript and web development but have been having fun doing some tutorials on React. Also my first time posting on stackoverflow!
I am building a component to show a list of yes/no questions and users have to respond by selecting radio buttons and optionally adding some comments in a textarea. I'm not really sure how I am supposed to set the state for an array of inputs generated using map.
I have an array holding my questions:
var questions = [
{id:"1", text:"Is the source up to date?"},
{id:"2", text:"Question 2 placeholder"},
{id:"3", text:"Question 3 placeholder"},
]
and here is my (unfinished) component:
var QuestionList = React.createClass({
getInitialState: function () {
return {
commentText: "",
}
},
onUpdateComments: function (e) {
this.setState({
commentText: e.target.value
});
},
render: function () {
var QuestionLines = this.props.questions.map(function(question) {
return (
<div key={question.id}>
<div>
<div>
{question.text}
</div>
<label>
<input type="radio" name={question.id} value = {question.id+'Y'}/>Yes
</label>
<label>
<input type="radio" name={question.id} value = {question.id+'N'}/>No
</label>
</div>
<div>
<textarea
name = {question.id}
onChange = {this.onUpdateComments}
placeholder="Enter comments here"
value={this.state.commentText} />
</div>
</div>
);
}, this);
return (
<div>
{QuestionLines}
</div>
)
}
});
The app right now displays the same text in all 3 textareas, and I can see that this is because I am storing all changes to textarea in the same commmentText state. However, I am really stumped as to what I need to do to separate these and make this work. Any help would be appreciate.
Also, as I mentioned I am super new to this so if anything is off about how I am structuring my component, please let me know.
Thanks!
Upvotes: 1
Views: 8087
Reputation: 7278
I would do something like that:
var QuestionList = React.createClass({
getInitialState: function () {
return { comments: {} } //set internal state comment as an empty object
},
onUpdateComments: function (id, e) {
/*
you can modify your state only using setState. But be carefull when trying to grab actual state and modify it's reference.
So, the best way is to create a new object (immutable pattern), and one way of doing that is to use Object.assign
*/
var comments = Object.assign({}, this.state.comments);
/* set, for instance, comment[1] to "some text" */
comments[id] = e.target.value;
/* set the state to the new variable */
this.setState({comments: comments});
},
render: function () {
var QuestionLines = this.props.questions.map(function(question) {
/* grab the comment for this ID. If undefined, set to empty */
var comment = this.state.comments[question.id] || "";
return (
<div key={question.id}>
<div>
<div>
{question.text}
</div>
<label>
<input type="radio" name={question.id} value = {question.id+'Y'}/>Yes
</label>
<label>
<input type="radio" name={question.id} value = {question.id+'N'}/>No
</label>
</div>
<div>
<textarea
name = {question.id}
onChange = {this.onUpdateComments.bind(this,question.id)}
placeholder="Enter comments here"
value={comment} />
</div>
</div>
);
}, this);
return (
<div>
{QuestionLines}
</div>
)
}
});
Upvotes: 1
Reputation: 2986
Just set commentText
as an object:
var QuestionList = React.createClass({
getInitialState: function () {
return {
commentText: {},
}
},
onUpdateComments: function (e) {
// Note that e.target.name is question.id
var target = e.target;
this.state.commentText[target.name] = target.value;
this.forceUpdate();
},
render: function () {
var QuestionLines = this.props.questions.map(function(question) {
var id = question.id; // store id
return (
<div key={id}>
<div>
<div>
{question.text}
</div>
<label>
<input type="radio" name={id} value = {id+'Y'}/>Yes
</label>
<label>
<input type="radio" name={id} value = {id+'N'}/>No
</label>
</div>
<div>
<textarea
name = {id}
onChange = {this.onUpdateComments}
placeholder="Enter comments here"
value={this.state.commentText[id]} />
</div>
</div>
);
}, this);
return (
<div>
{QuestionLines}
</div>
)
}
});
See difference between onUpdateComments
and value={this.state.commentText[id]}
.
Note:
If you use babel to compile your code, you can write onUpdateComments
like that:
onUpdateComments: function (e) {
// Note that e.target.name is question.id
var target = e.target;
this.setState(function(previousState) {
return {
commentText: {
...previousState.commentText,
[target.name]: target.value
}
}
});
},
Upvotes: 0
Reputation: 1768
One solution would be to have a commentTextStore object, where the keys(properties) are the commentIds and then you have each question text area write to the value corresponding the commentId.
Upvotes: 0