update state from child in React - javascript

I'm trying to create a menu where the user should create a character details but I'm having an issue to update the Options states through an input of a child.
var Name = React.createClass({
render: function(){
return(
<input type="text"/>
)
}
});
var Options = React.createClass({
getInitialState: function(){
return{
name: ''
}
},
render: function(){
return (
<div>
Name: <Name onChange={this.updateName} value={this.state.name} />
</div>
)
},
updateName: function(evt){
this.setState({
name: evt.target.value
});
}
});
How can I go about updating the Option states using the input from Name?

you need onChange function on the Name component as well, that sends the value to the parent component
Try this:
var Name = React.createClass({
onUpdate: function(evt) {
this.props.onChange(evt);
}
render: function(){
return(
<input type="text" onChange={this.onUpdate} value={this.props.value}/>
)
}
});
var Options = React.createClass({
getInitialState: function(){
return{
name: ''
}
},
render: function(){
return (
<div>
Name: <Name onChange={this.updateName} value={this.state.name} />
</div>
)
},
updateName: function(evt){
this.setState({
name: evt.target.value
});
}
});

Component Communication in React
Refer this link to know what are the ways to communicate between React components.

Related

React: Warning: setState(...): Cannot update during an existing state transition

My project keeps crashing when I attempt to insert a new recipe element. I use the this.state.recipes.map... in RecipeList to be able to update the recipes as needed(e.g. delete,edit,etc.). The delete functionality works, but I am unable to add a new recipe element.
If I switch the statement to this.props.recipes.map..., I am able to insert elements without an issue, but am unable to delete since the delete triggers a state change, and needs the state change to reflect the update instead of the props. Anyone have any tips on this issue? Thanks!
Recipe List:
var RecipeList = React.createClass({
getInitialState: function(){
return {recipes: []};
},
deleteRecipe: function(recipe){
var curRecipes = this.state.recipes.slice('');
curRecipes.splice(recipe.recipeKey,1);
this.setState({recipes: curRecipes});
},
componentWillMount: function(){
this.setState({recipes: this.props.recipes});
},
render: function(){
var recipeNodes = this.state.recipes.map(function(recipe,index){
return <Recipe onDelete={this.deleteRecipe} recipeKey={index} key={index} recipeTitle={recipe.recipeTitle} ingredients={recipe.ingredients} instructions={recipe.instructions} />
},this);
return(
<div>
{recipeNodes}
</div>
);
}
});
Recipe Container:
var RecipeBox = React.createClass({
getInitialState: function(){
return {showForm: false,
recipes: []
};
},
openForm: function(){
this.setState({showForm: true});
},
handleRecipeSubmit: function(recipe){
var curRecipes = this.state.recipes.slice('');
curRecipes.push({recipeTitle: recipe.recipeTitle,ingredients: recipe.ingredients, instructions: recipe.instructions});
this.setState({recipes: curRecipes});
},
render: function(){
return(
<div id="recipeBox">
<RecipeList recipes={this.state.recipes} />
<div className="recipeButtons">
<button id="addRecipeButton" className="btn-style" onClick={this.openForm}>Add Recipe</button>
</div>
{this.state.showForm ? this.refs.dialogWithCallBacks.show() : null}
<SkyLight
dialogStyles={formDialog}
ref="dialogWithCallBacks"
title="Add Recipe">
<RecipeForm onRecipeSubmit={this.handleRecipeSubmit} skylightRef={this.refs.dialogWithCallBacks} />
</SkyLight>
</div>
);
}
});
Recipe Form:
var RecipeForm = React.createClass({
getInitialState: function(){
return {hideDialog: false};
},
getFormData: function(){
var ingredients= document.getElementsByClassName("ingredient"),
recipeName = document.getElementsByName('recipeName')[0].value,
instructions = document.querySelector('textarea').value,
data = [];
ingredients = [].slice.call(ingredients).map(function(ingredient,index){
return {
"quantity": ingredient.childNodes[0].value,
"ingredient": ingredient.childNodes[1].value,
"unit": ingredient.childNodes[2].value
};
});
// Combine results into output array
data.push(recipeName);
data.push(ingredients);
data.push(instructions);
return data;
},
submitRecipe: function(event){
event.preventDefault();
var data = this.getFormData();
// Hide the SkyLight modal container
this.setState({hideDialog: true});
// Submit form
this.props.onRecipeSubmit({recipeTitle: data[0], ingredients: data[1], instructions: data[2]});
},
render: function(){
return(
<form onSubmit={this.submitRecipe}>
<section className="recipe-main">
<h2 style={{'border-bottom': 'none'}}>Recipe Name</h2>
<RecipeFormName />
<h2 style={{'border-bottom': 'none'}}>Ingredients</h2>
<RecipeFormIngredients />
</section>
<RecipeFormInstructions />
<input type="submit" value="Add Recipe" />
{this.state.hideDialog ? this.props.skylightRef.hide() : null}
</form>
)
}
});
You should move the code in componentWillMount to getInitialState.
getInitialState: function(){
return {recipes: this.props.recipes};
},
Needed to change the RecipeList component to
<RecipeList recipes={this.state.recipes} onChange={this.handleChange}/>
and then handle the deletion change from the RecipeBox instead of directly in RecipeList. Have to use this.props.map... to display new recipes and also delete visible ones.
var RecipeList = React.createClass({
getInitialState: function(){
return {recipes: this.props.recipes};
},
deleteRecipe: function(recipe){
var curRecipes = this.props.recipes.slice('');
curRecipes.splice(recipe.recipeKey,1);
this.props.onChange({recipes: curRecipes});
},
render: function(){
var recipeNodes = this.props.recipes.map(function(recipe,index){
return <Recipe onDelete={this.deleteRecipe} recipeKey={index} key={index} recipeName={recipe.recipeName} ingredients={recipe.ingredients} instructions={recipe.instructions} />
},this);
return(
<div>
{recipeNodes}
</div>
);
}
});

React multipages, component data passing

I'm doing a react app and id I'd like to know how to think multipages websites. Actually i'im I'm doing a course searcher,i searcher; I use routie to render the different components that renders render the page. The problem is that they arent aren't related by hierarchy, so the ajax data isn't accessible to the component that renders the result.I've I've tried vainly to use a js var data but doesnt var data but that doesn't work too either.Ive read https://facebook.github.io/react/tips/communicate-between-components.html
but i don't see what to do with own event system. If someone could illustrate the last paragraph of this doc it is great for all the people that are in this case.
var data = {};
var CourseSearcher = React.createClass({
getInitialState: function(){
return {
return { places: '',
branch: 0,
dayOfMonth: '',
timeStart: '',
timeEnd: '',
data: []};
},;
},
handlePlacesChange: function(e){
this.setState({places: e.target.value});
},
handleBranchChange: function(e){
this.setState({branch: e.target.value});
},
handleDayOfMonthChange: function(e){
this.setState({dayOfMonth: e.target.value});
},
handleTimeStartChange: function(e){
this.setState({timeStart: e.target.value});
},
handleTimeEndChange: function(e){
this.setState({timeEnd: e.target.value});
},
handleSubmit: function(e){
// stop the default browser action
e.preventDefault();
// Do an ajax post
$.ajax({
url:'php/results.php',
dataType: 'json',
type: 'GET',
data: {
data: {places: this.state.places,
branch:this.state.branch,
dayOfMonth:this.state.dayOfMonth,
timeStart:this.state.timeStart,
timeEnd:this.state.timeEnd},
},
success: function(data){
this.setState({data: data});
data = this.state.data;
routie('results');
}.bind(this),
error: function (xhr,status,err){
console.error('php/results.php',status,err.toString());
}.bind(this)
});
},
render: function(){
return(
<div>
<form method="get" onSubmit={this.handleSubmit}>
<label>Où?</label>
<input
type="text"
placeholder="Lieux"
value={this.state.places}
onChange={this.handlePlacesChange}
/>
<label>Quoi?</label>
<select value={this.state.branch} onChange={this.handleBranchChange}>
<option>Matière</option>
<option>Français</option>
<option>Anglais</option>
</select>
<label>Quand ?</label>
<input
type="date"
value={this.state.dayOfMonth}
onChange={this.handleDayOfMonthChange}
/>
<input
type="time"
value={this.state.timeStart}
onChange={this.handleTimeStartChange}
/> -
<input
type="time"
value={this.state.timeEnd}
onChange={this.handleTimeEndChange}/>
<button type="submit">Go!</button>
</form>
</div>
);
}
});
console.log(data);
var ResultList = React.createClass({
render: function() {
console.log(data);
return(
<h1>Hello</h1>);
}
);
}
});
var ResultBox = React.createClass({
render: function() {
return (
<div>
<h4>{}</h4>
</div>
);
}
});
routie({
'':function() {
React.render(<CourseSearcher />,
document.getElementById('content'));
},
'results': function() {
React.render(
React.render(<ResultList results={data} />,
document.getElementById('content'));
}
});
Done well with react router ;)
I've done it with react router where components are related to some dedicated urls

Reactjs: setState with checkbox: checked or unchecked

I'm currently "testing the waters" with Reactjs. Based on their docs, I have whipped up a small project that I'm stuck with. So far, when the checkbox is checked, the state changes but....not sure how to change a state unchecked:
var Foo = React.createClass{(
getInitialState: function() {
return {
location: true,
}
},
onClick: function() {
this.setState({ location: false });
},
render: function() {
var inlineStyles = {
display: this.state.location ? 'block' : 'none'
};
return (
<div>
<input type="checkbox"
onClick={this.onClick}
/> show / hide bar
<hr />
<div style={inlineStyles}>
<p>bar</p>
</div>
</div>
);
}
)};
Do I need to use an if statement for the sort of thing I want? I need to this.setState.location: true when unchecked.
You need to read the state of the checkbox during a click, and apply that to your React state.
var Foo = React.createClass({
render: function() {
return <input type="checkbox" onClick={this.onClick} checked={!this.state.location}></input>
},
onClick: function(e) {
this.setState({location: !e.target.checked});
},
getInitialState: function() {
return {
location: true
};
}
});

ReactJs check all checkboxes

I have a select all component rendering in my table header, I would like it to check all of the checkboxes on the page when checked, if one of the checkboxes is unchecked I would like the select all to unselect too:
var SelectAll = React.createClass({
handler: function(e) {
e.target.value;
e.preventDefault();
channel.publish({
channel: "contact",
topic: "selectAll",
data: {
contacts: this.props.data
}
});
},
render: function() {
console.log(this.props.data.children);
var id = this.props.contacts;
var isSelected = this.props.data.isSelected;
return (
<div className="contact-selector">
<input type="checkbox" checked={isSelected}
onChange={this.handler} />
</div>
);
},
});
My checkboxes are rendered in each table row:
var ContactSelector = React.createClass({
getInitialState: function() {
return {
selectedContacts:[]
};
},
handleChange: function(e) {
var id = e.target.attributes['data-ref'].value;
if (e.target.checked === true){
contactChannel.publish({
channel: "contact",
topic: "selectedContact",
data: {
id: id
}});
} else{
contactChannel.publish({
channel: "contact",
topic: "deselectedContact",
data: {
id: id
}});
}
},
render: function() {
var id = this.props.data.id;
var isSelected = this.props.data.IsSelected;
return (
<div className="contact-selector">
<input type="checkbox"
checked={isSelected} data-ref={id}
onClick={this.handleChange} />
</div>
);
}
});
Can anyone please tell me how to setup the check all? Using state or refs etc

Cross-component communication via return key

In my React.js to-do app, I'm trying to enable the return key to submit an item from my TextInput component to my ToDoList component. Right now the TextInput.inputSubmit method just console.logs the input value, but I'm wondering if I can have it trigger a prop (enter={that.addToDo}) inside of ToDoList. Or is there a better way?
JSFiddle
Edit: improved JSFiddle (courtesy of knowbody)
/** #jsx React.DOM */
var todos = [{text: "walk dog"}, {text: "feed fish"}, {text: "world domination"}, {text: "integrate return key"}];
var TextInput = React.createClass({
getInitialState: function() {
return {text: ''};
},
inputSubmit: function() {
//I think I want to trigger ToDoList's addToDo method from here?
console.log(this.refs.inputEl.getDOMNode().value);
this.setState({text: ''});
},
handleChange: function(evt) {
this.setState({text: evt.target.value});
},
handleKeyDown: function(evt) {
if (evt.keyCode === 13 ) {
return this.inputSubmit();
}
},
render: function() {
return (
<input value={this.state.text} ref="inputEl" onChange={this.handleChange} onKeyDown={this.handleKeyDown}/>
)
}
});
var SubmitButton = React.createClass({
render: function(){
return (
<button onClick={this.props.click}> Add </button>
)
}
});
var ToDo = React.createClass({
render: function(){
return (
<div>
<button onClick={this.props.click}>X</button>
<span> - {this.props.text}</span>
</div>
)
}
});
var ToDoList = React.createClass({
getInitialState: function (){
return {
todos: this.props.todos.splice(0)
}
},
deleteToDo: function(todo){
this.state.todos.splice(this.state.todos.indexOf(todo), 1);
this.setState({todos: this.state.todos});
},
addToDo: function(){
this.state.todos.push({text: this.refs.textIn.refs.inputEl.getDOMNode().value});
this.setState({
todos: this.state.todos
});
this.refs.textIn.setState({text: ''});
},
render: function(){
var that = this;
return (
<div>
{this.state.todos.map(function(todo) {
return (
<ToDo text={todo.text} click={that.deleteToDo.bind(null, todo)} />
)
})}
<br/>
<TextInput ref="textIn" enter={that.addToDo} />
<SubmitButton click={that.addToDo} />
</div>
)
}
});
React.renderComponent(<ToDoList todos={todos} />, document.body);
Your code is a bit messy but a quick fix will be to add:
this.props.enter(this.refs.inputEl.getDOMNode().value);
where your console.log() is. I will edit my answer with the full explanation once I'm on my laptop

Categories