This works perfectly fine. Now, I would like to incorporate this into a function and just call the function within my expression. It doesn't work.
Working code:
render: function() {
return (
<div>
{this.props.list.map(function(listValue){
return <p>{listValue}</p>;
})}
</div>
)
}
});
ReactDOM.render(<List list={[1,2,3,4,5]} />, document.getElementById('app'));
code with the function (doesn't work):
var List = React.createClass({
addText: function()
{
this.props.list.map(function(listValue){
return <p>{listValue}</p>;
});
},
render: function() {
return (
<div>
{this.addText()}
</div>
)
}
});
ReactDOM.render(<List list={[1,2,3,4,5]} />, document.getElementById('app'));
You've extracted the call to map into another function and maybe assumed the return call inside it was sufficient to return the result of the whole call (it just returns the mapped value for that iteration of map).
You just need to return the result of your map in your addText function:
var List = React.createClass({
addText: function()
{
return ( // <------ADD THIS
this.props.list.map(function(listValue){
return <p>{listValue}</p>;
})
); //<<-----DON'T FORGET TO CLOSE OFF THE NEW BRACKET
},
render: function() {
return (
<div>
{this.addText()}
</div>
)
}
});
Tnx #Thomas altmann, I forgot to make another return prior to my first return
var List = React.createClass({
addText: function()
{
return (this.props.list.map(function(listValue){
return <p>{listValue}</p>;
})
);
},
render: function() {
return (
<div>
{this.addText()}
</div>
)
}
});
ReactDOM.render(<List list={[1,2,3,4,5]} />, document.getElementById('app'));
Related
I decided to learn React and started with the official tutorial. All is good until I get to this state of my code:
var CommentBox = React.createClass({
render: () => {
return (
<div className="commentBox">
<h1> Comments </h1>
<CommentList />
<CommentForm />
</div>
);
}
});
var CommentForm = React.createClass({
render: () => {
return (
<div className="commentForm">
Hello, world! I am a comment form;
</div>
);
}
});
var Comment = React.createClass({
rawMarkup: () => {
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
return {__html: rawMarkup};
},
render: () => {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2> // <--- [[[[[[ ERROR IS HERE ]]]]]]
<span dangerouslySetInnerHtml={this.rawMarkup} />
</div>
);
}
});
var CommentList = React.createClass({
render: () => {
return (
<div className="commentList">
<Comment author="Pete Hunt">This is one comment</Comment>
<Comment author="Jordan Walke">This is *another* comment yo</Comment>
</div>
);
}
});
ReactDOM.render(
<CommentBox />,
document.getElementById('content')
);
When I try to run it, I get the following error in devtools:
TypeError: Cannot read property 'props' of undefined
...and the debugger pauses at the marked line (see code). When I mouseover this in {this.props.author}, I get a preview of the object which has the props property and everything...
Use function declaration ( render() {} or render: function {}) instead of arrow function render: () => {}
var Comment = React.createClass({
rawMarkup() {
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
return {__html: rawMarkup};
},
render() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHtml={this.rawMarkup} />
</div>
);
}
});
Example
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target).
Arrow functions are always anonymous.
I had the same error message:
Cannot read property 'props' of undefined
...but from a different cause: when this is called from within a function, javascript can not reach the variable because this is in an outer scope. (Note: I was in ES5)
In this case, simply store this in another variable, prior to the function (in the scope of your component): var that = this;
Then you will be able to call that.props from within the function.
Hope this helps for other people who had that error message.
Detailed example below:
render: function() {
var steps = [];
var that = this; // store the reference for later use
var count = 0;
this.props.steps.forEach(function(step) {
steps.push(<Step myFunction={function(){that.props.anotherFunction(count)}}/>); // here you are
count += 1;
});
return (
<div>{steps}</div>
)
}
A little late post/answer.
Try to bind your function inside the constructor
example:
this.yourfunction = this.yourfunction.bind(this);
I am on ES6 and the arrow function did the trick: rawMarkup = () => {}
I have 2 files:
grid-body.jsx (GridBody) and grid-row.jsx (GridRow)
In GridBody, I declared a function showAlert which I pass to every GridRow:
var GridBody = React.createClass({
showAlert: function(msg) {
alert(msg);
},
render: function() {
var rows = this.props.rows.map(function(li) {
return (
<GridRow showAlert={this.showAlert} />
);
});
return (
<div>
{rows}
</div>
);
}
});
And in GridRow:
var GridRow = React.createClass({
toggle: function() {
this.props.showAlert('HEY'); // -----> ERROR - not a function
},
render: function() {
<div>
<a href="#" onClick={this.toggle} />
</div>
}
});
I'm trying to call the showAlert from parent and based on the examples I've seen, this is how to do it but I can't make it work.
you're using the wrong value for this inside of GridView.render. Either pass it explicitly to Array.map() (see the docs for how to do that) or assign this to some new variable at the very top of render() and reference that instead.
Here is a really, really great SO comment as to why this happens, as well as some other alternative workarounds if neither of the above work for you.
The context of the function passed to map in render method of GridBody is window and not the component. You can bind the interatee to get the behavior you want:
render: function() {
var rows = this.props.rows.map(function(li) {
return (
<GridRow showAlert={this.showAlert} />
);
}.bind(this));
return (
<div>
{rows}
</div>
);
}
can you pass a component through props to children
var TaskForm = require('../../../../components/assessment/tasks/TaskForm.react');
render: function() {
return (
<div>
<div className="row">
<div className="col-xs-12 col-lg-12">
<GroupsItemsAccordionWrapper
TaskForm=TaskForm
/>
</div>
</div>
</div>
);
}
Yes, you can pass any value as a prop, including an object returned by React.createClass (aka component class). Assuming you are implementing dependency injection:
var TaskForm = React.createClass({
render: function() {
return (
<div>{this.props.children}</div>
);
}
});
var GroupsItemsAccordionWrapper = React.createClass({
render: function() {
var TaskForm = this.props.TaskForm;
return (
<div>
<TaskForm>Hello, world!</TaskForm>
</div>
);
}
});
ReactDOM.render(
<GroupsItemsAccordionWrapper TaskForm={TaskForm} />,
document.getElementById('container')
);
(Note the curly brackets around TaskForm={TaskForm}).
Demo: https://jsfiddle.net/69z2wepo/37477/
You can do this like that :
var DivWrapper = React.createClass({
render: function() {
return <div>{ this.props.child }</div>;
}
});
var Hello = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
// create you component
var comp = <Hello name="World" />
ReactDOM.render(<DivWrapper child={ comp }/>, document.body);
And use { this.props.child } to render the component
JSFiddle here : https://jsfiddle.net/5c4gg66a/
I have a react component that passes a function to a child component, and I bind it to onClick. But when I click I get an error:
this.props.beBad is not a function, this.props.beBad is not defined
it looks something like this:
var Dad = React.createClass({
beBad: function(someInput) {
alert('being bad ' + someInput);
},
render: function() {
var Children = this.state.children.map(function(data, index) {
return (
<Child beBad={this.beBad} key={index}/>
);
});
return (
<div>
{Children}
</div>
);
});
var Child = React.createClass({
beBad: function() {
this.props.beBad('some input');
},
render: function() {
return(
<div onClick={this.beBad}>
be bad
</div>
);
}
});
It doesn't look like this is what you expect. When using React.createClass, React will autobind the correct this IFF the call is at the top level of the function, so in this case it will autobind correctly:
render: function() {
return (
<div onClick={this.beBad}> // autobound
be bad
</div>
);
}
But not here:
var Children = this.state.children.map(function(data, index) {
return (
<Child beBad={this.beBad} key={index}/> // `this` is not what you expect
);
});
return (
<div>
{Children}
</div>
);
The reason is because map is creating a new scope, and this is no longer what you'd expect, and React can't autobind it for you. You need to pass this around explicitly:
var Children = this.state.children.map(function(data, index) {
return (
<Child beBad={this.beBad.bind(this)} key={index}/> // bind `this`
);
}, this); // pass `this`
Note: Seeing the other response, it is possible that React autobinds it for you inside the map, but in general I wouldn't rely on autobinding, explicit wins over implicit. Plus if you ever write React with ES6 classes it doesn't do autobinding.
You've got a problem with your this because you're on the "map scope".
Try to pass this to your map :
var Children = this.state.children.map(function(data, index) {
return (
<Child beBad={this.beBad} key={index}/>
);
}, this);
For your information see : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
as shown in the example below, I'd like MyComponent to dynamically attach an "onClick" event to its children. The onClick event should fire alertView that should be able to call the clicked element method "getValue".
JSFiddle: http://jsfiddle.net/2g638bp8/
How to do this? Thanks
var MyComponent = React.createClass({
alertValue: function () {
// RETRIEVE THE CHILD HERE
alert(child.getValue());
},
render: function () {
var children = React.Children.map(this.props.children, function (c, index) {
return React.addons.cloneWithProps(c, {
ref: 'child-' + index
});
});
return (
<div>
{children}
</div>
);
}
});
var MySubComponent = React.createClass({
getValue: function () {
return this.props.val;
},
render: function () {
return (
<div>{this.props.val}</div>
);
}
});
React.render(
<div>
<MyComponent>
<MySubComponent val="1" />
<MySubComponent val="2" />
<MySubComponent val="3" />
</MyComponent>
</div>,
document.getElementById('container')
);
You can't call methods on child components in React. You can only set properties. (The child is actually a ReactElement which contains information about the class and associated properties. It is not an instance of the component you created).
So, you could think about this a slightly different way and move the onClick to the MySubComponent:
var MyComponent = React.createClass({
onHandleGiveValue: function (value) {
alert(value);
},
render: function () {
const children = React.Children.map(this.props.children, child => React.cloneElement(child, { onGiveValue: this.onHandleGiveValue.bind(this) }));
return (
<div>
{children}
</div>
);
}
});
var MySubComponent = React.createClass({
handleClick: function() {
this.props.onGiveValue(this.props.val);
},
getValue: function () {
return this.props.val;
},
render: function () {
return (
<div onClick={ this.handleClick } >{this.props.val}</div>
);
}
});
React.render(
<div>
<MyComponent>
<MySubComponent val="1" />
<MySubComponent val="2" />
<MySubComponent val="3" />
</MyComponent>
</div>,
document.getElementById('container')
);
By doing that, your code can pass the current value as an event to the parent component. I've created a new event from the MySubComponent class named onGiveValue. That for now just passes the value from this.props.val. But, it could of course be anything.
Pass the parent callback to the subComponent, one dont need a reference for the child component.
React prefers composition design pattern, So your parent component should contains those three subComponent.
JS Fiddle: http://jsfiddle.net/68vt3umg/
var MyComponent = React.createClass({
handleChildClick: function (e, childValue) {
alert(childValue);
},
render: function () {
return (
<div>
<MySubComponent val="1" onSubClicked={this.handleChildClick}/>
<MySubComponent val="2" onSubClicked={this.handleChildClick}/>
</div>
);
}});
var MySubComponent = React.createClass({
getValue: function () {
return this.props.val;
},
handleOnClick: function (e, value) {
this.props.onSubClicked(e, this.props.val);
},
render: function () {
return (
<div onClick={this.handleOnClick}>{this.props.val}</div>
);
}
});
React.render(
<div>
<MyComponent />
</div>,
document.getElementById('container')
);