This is my code:
var Item = React.createClass({
render: function () {
return (
React.createElement('div', {},
React.createElement('span', {}, this.props.a),
React.createElement('span', {}, this.props.b)
)
);
}
});
var RParent = React.createClass({
getInitialState: function () {
return {messages: []};
},
addMess: function (data) {
var self = this;
self.state.messages.push({
a: data.a,
b: data.b
});
this.setState({messages: self.state.messages});
},
render: function () {
var messages = this.state.messages;
return (
React.createElement('div', {},
React.createElement(Item, messages))
);
}
});
var box = ReactDOM.render(React.createElement(RParent), document.getElementById('parentDiv'));
function render(a, b) {
box.addMess({
a: a,
b: b
});
}
Data is sent to the render function. It appears that somehow the properties are not reaching the render function of the Item as they appear to be undefined when I try print them to console.
Any ideas why this might be happening?
The problem is that nothing is rendered into the "parentDiv". It just remains blank. However, on inspecting the elements, I can still see two "span" children under it (which were not created in html or anywhere else except here). But those span elements have no content.
I think there's a fundamental problem to your code. You are trying to pass 'a' and 'b' to your react component through an external function 'render' that seems to be invoking one of the component's functions. This is wrong.
You should pass 'a' and 'b' to your React component RParent as props. Whenever the value of 'a' and 'b' change, your parent component will automatically rerender.
var Item = React.createClass({
render: function () {
return (
React.createElement('div', {},
React.createElement('span', {}, this.props.a),
React.createElement('span', {}, this.props.b)
)
);
}
});
var RParent = React.createClass({
getInitialState: function () {
return {messages: []};
},
,
render: function () {
var messages = this.props.messages;
return (
React.createElement('div', {},
React.createElement(Item, messages))
);
}
});
ReactDOM.render(
(<RParent messages= {'a': a, 'b': b} />)
, document.getElementById('parentDiv'));
Related
Using Material UI with this example React component:
const React = require('react');
const DropDownMenu = require('material-ui/DropDownMenu').default;
const MenuItem = require('material-ui/MenuItem').default;
const MyDropDown = React.createClass({
getDefaultProps: function() {
return {
onChange: () => {},
items: []
};
},
getInitialState: function() {
return {
value: undefined
};
},
render: function() {
const {
state: {value},
props: {items, id}
} = this;
return React.createElement(DropDownMenu, {
id,
maxHeight: 300,
onChange: (event, index, value) => {
this.setState({value});
},
value: typeof value === 'undefined'
? items[0].value
: value,
children: items.map((item, key) => (
React.createElement(MenuItem, {
value: item.value,
primaryText: item.label,
key
})
))
});
}
});
When I select or hover one of the items, I get this error.
Exception thrown by hook while handling onSetChildren:
Invariant Violation: Expected onBeforeMountComponent() parent
and onSetChildren() to be consistent (74 has parents 41 and 73).
This reproduces across any Material UI component with clickable children.
The reading material for the error is frustratingly sparse. What does this error mean, and why is it happening?
First time chart components is rendered correctly. When I am changing the tab on dashboard and again click on show charts I am getting error this.dataTable.getNumberOfRows is not a function. When I am mounting chart component again then I am getting error.
chart component:
var React = require('React');
var ReactDOM = require('ReactDOM');
var {Chart} = require('react-google-charts');
var $ = require('jquery');
var LineChart = React.createClass({
getInitialState: function() {
return {
rows: [],
}
},
componentWillMount: function () {
this.sTime = this.props.sTime;
this.eTime = this.props.eTime;
var _this = this;
var request = function () {
$.post("/times" , {'start':_this.sTime, 'end':_this.eTime }, function (res) {
_this.setState({
rows: res.data
});
});
};
request();
},
render: function() {
return (
<div >
<Chart chartType="LineChart"
rows={this.state.rows}
columns={this.props.columns}
options={this.props.options}
/>
</div>
);
}
});
module.exports = LineChart;
I need to define initial value of rows. This solve the problem.
getInitialState: function() {
return {
rows: [[new Date(0),0]],
}
},
I've got a simple react component/sub-component structure. On the subcomponent, I'm trying to loop through an array of objects and output a property value on that object.
There is always a single empty text node displayed at the top of the list I'm outputting and I can't figure out why it's there or how to make it go away.
A view from React's Dev Tools
Here's my Code:
'use strict'
var React = require('react'),
ReactDOM = require('react-dom')
var UpcomingMovieList = React.createClass({
render: function() {
return(<UpcomingMovie movies={this.props}/>)
}
})
var UpcomingMovie = React.createClass({
render: function() {
console.log(this)
var movie = this.props.movies.movies.map(function(element, index) {
// console.log(element)
return(<div className='movie' key={element.id}><div className='movie-content'>{element.title}</div></div>)
})
return(<div>UpcomingMovie.{movie}</div>)
}
})
ReactDOM.render(<UpcomingMovieList movies={window.data.movies}/>,
document.getElementById('app-container')
)
window.data.movies is just an array of objects. I'm just trying to output the title for the moment.
Try this instead:
var UpcomingMovie = React.createClass({
render: function() {
return (
<div>
<h2>Upcoming Movies</h2>
{this.props.movies.movies.map(function(element, index) {
// console.log(element)
return(<div className='movie' key={element.id}><div className='movie-content'>{element.title}</div></div>)
})}
</div>
);
}
});
It would be more ideal to do the iteration from the UpcomingMovieList component though:
var UpcomingMovieList = React.createClass({
render: function() {
return this.props.movies.map((movie) => {
return <UpcomingMovie movie={movie} />
});
}
});
var UpcomingMovie = React.createClass({
render: function() {
var movie = this.props.movie;
return (
<div className='movie' key={movie.id}>
<div className='movie-content'>{movie.title}</div>
</div>
);
}
});
So, I believe this is a formatting issue OR I'm not clear about how the return works when dynamically building.
The render function in Results works, if I replace the code with anythign else it renders where I want. Similarly, the console.log's in the Results function outputs the data correctly. There's no error, it just doesn't render the html and it doesn't hit the debugger in SynonymElement.
What am I missing in here / what core concept am I misconstruing?
(This is just an input form that takes a word, user hits submit, it returns an object with the word as a key and the value an array of synonynms. that get rendered in the ul)
'use strict'
const Smithy = React.createClass({
dsiplayName: "Smithy",
getInitialState: function() {
return { data: []};
},
handleSubmit: function(data) {
$.get('/get-synonyms', { data: data.data }).done(function(data) {
this.setState({ data: data})
}.bind(this));
},
render: function() {
return (
<div className="smithy">
<h1>Craft Tweet</h1>
<SmithyForm onSubmit={this.handleSubmit} />
<Results data={this.state.data} />
</div>
)
}
})
const SmithyForm = React.createClass({
displayName: "SmithyForm",
getInitialState: function() {
return { placeholder: "tweet", value: "" };
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
handleSubmit: function(event) {
event.preventDefault();
var tweet = this.state.value.trim();
this.props.onSubmit({ data: tweet });
this.setState({value: ''});
},
render: function() {
var placeholder = this.state.placeholder;
var value = this.state.value;
return (
<form className="smithyForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder={placeholder} value={value} onChange={this.handleChange} />
<button>smithy</button>
</form>
);
}
})
const SynonymElement = React.createClass({
render: function() {
debugger
return (
<li>{this.props.data}</li>
)
}
})
const Results = React.createClass({
render: function() {
var words = this.props.data;
return (
<div className="results">
{
Object.keys(words).map(function(value) {
{ console.log(value) }
<div className={value}>
<ul>
{
words[value].map(function(syn) {
{ console.log(syn) }
return <SynonymElement data={syn} />
})
}
</ul>
</div>
})
}
</div>
)
}
})
ReactDOM.render(<Smithy />, document.getElementsByClassName('container')[0])
Might have some other complicating issues but assuming everything else is wired up correctly, you need to return the result of the function you pass into the first map (over the collection Object.keys(words)) just as you have for the later map otherwise the function is executed and nothing useful is returned.
Possibly just a dupe of loop inside React JSX
return (
<div className="results">
{
Object.keys(words).map(function(value) {
return ( // <-- this
<div className={value}>
Here I try to set state.autocomplete to 'hello' and then print it, but state seems to be null. How can that be when I just updated the state using setState? data is set as a global variable.
var data = {
populate_at: ['web_start', 'web_end'],
autocomplete_from: ['customer_name', 'customer_address']
};
var AutocompleteFromCheckboxes = React.createClass({
handleChange: function(e) {
this.setState( { autocomplete_from: 'event.target.value' } );
console.log('autocompleteFrom state: ', this.state.autocomplete_from);
// ^ => Uncaught TypeError: Cannot read property 'autocomplete_from' of null
return 1;
},
render: function() {
var autocompleteFrom = this.props.autocomplete_from.map(function(value) {
return (
<label for={value}>
<input type="checkbox" name={value} value="{value}"
onChange={this.handleChange.bind(this)}
ref="autocomplete-from"/>
{value}
</label>
);
}, this);
return (
<div className="autocomplete-from">
{autocompleteFrom}
</div>
);
}
});
var DynamicForm = React.createClass({
getInitialState: function() {
return {
name : null,
populate_at : null,
same_as : null,
autocomplete_from : "not set",
title : null
};
},
saveAndContinue: function(e) {
e.preventDefault();
var data = {
name : this.refs.name.getDOMNode().value,
};
console.log('data: ' + data.name);
},
render: function() {
return (
<AutocompleteFromCheckboxes
autocomplete_from={this.props.data.autocomplete_from} />
);
}
});
var mountpoint = document.getElementById('dynamic-form');
if ( mountpoint ) {
React.render(<DynamicForm data={data} />, mountpoint);
}
});
From the reactjs docs:
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.
https://facebook.github.io/react/docs/component-api.html
What you can do is pass a callback function to setState which is triggered once the state has been updated:
this.setState(
{autocomplete_from: ...},
function () {
... at this point the state of the component is set ...
}
)
You need to set the initial state of your component, try adding the following to the top of your component.
getInitialState: function() {
return {
autocomplete_from: ''
};
}
EDIT:
In your DynamicFrom component you have:
render: function() {
return (
<AutocompleteFromCheckboxes
autocomplete_from={this.props.data.autocomplete_from} />
);
}
Since you are trying to reference the state you should write
autocomplete_form={this.state.autocomplete_from}
Also you are trying to set the state from a child component and it should not directly modify state. The best way to approach this is to pass down a function from DynamicFrom(holds the state) to AutocompleteFromCheckboxes. Like so.
var DynamicForm = React.createClass({
handleChange: function(value) {
this.setState({autocompelete_from: value});
},
render: function() {
return(
<AutocompleteFromCheckboxes
autocomplete_from={this.state.autocomplete_from}
handleChange={this.handleChange}
/>
);
},
....
});
Then call that function in your child component
AutocompleteFromCheckboxes = React.createClass({
....
onChange={this.handleChange}
....
handleChange: function(e) {
this.props.handleChange(e.target.value);
}
});
To see updated state value after doing setState you should do something like below
this.setState( { autocomplete_from: 'event.target.value' }, () => {
console.log(this.state.autocomplete_from);//this will print the updated state value
});