bind() in render method gives me a warning? - javascript

My code is working properly but it gives me a warning
Warning: bind(): You are binding a component method to the component. React does this for you automatically in a high-performance way, so you can safely remove this call.
I also use onClick={this.myFun.bind(null,"myvalue")} as describe in the Why does React warn me against binding a component method to the object?
Still it give me warning.
My Code :
var MyClass = React.createClass({
myFun : function (value){
console.log(value);
},
render: function () {
var that = this;
var card = this.props.data.map(function (val,key) {
return (
<p onClick={that.myFun.bind(null,val)}> Click Me</p>
);
});
return (
<div>
{card}
</div>
);
}
});

There are a few things wrong with your code
render: function () {
var this = that;
should be
render: function () {
var that = this;
return ( {card}) will give an error that you may have returned undefined or null or an Object and hence you need to wrap it inside a div like <div>{card}</div> to return a React Element.
You component name must begin with a upper case Character. See the explanation here: React - Adding component after AJAX to view
See the working demo
var MyClass = React.createClass({
myFun : function (value){
console.log(value);
},
render: function () {
var that = this;
var card = this.props.data.map(function (val,key) {
return (
<p key={key} onClick={that.myFun.bind(null,val)}> Click Me</p>
);
});
return (
<div>{card}</div>
);
}
});
ReactDOM.render(<MyClass data={['1', '2']}/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="app"></div>
NOTE: React.createClass is deprecated and will be removed in v16.0
and hence you should write your component by extending
React.Component syntax

The only you missed is assign that to this
var myClass = React.createClass({
myFun : function (value){
console.log(value);
},
render: function () {
var that = this;
var card = this.props.data.map(function (val,key) {
return <p onClick={that.myFun.bind(null,val)}> Click Me</p>;
});
return <div>{card}</div>;
}
});

The best way to do this is to extract it into a sub-component and pass the params as props. This way you won't be creating a new function on every render, and will prevent unnecessary re-renders (More info here jsx-no-bind):
var Item = React.createClass({
handleClick: function() {
this.props.onItemClick(this.props.val);
},
render: function() {
return (
<p onClick={this.handleClick}>Click Me</p>
);
}
});
var MyClass = React.createClass({
myFun: function (value){
console.log(value);
},
render: function () {
var that = this;
var card = this.props.data.map(function (val, key) {
return (
<Item onItemClick={that.myFun} val={val} />
);
});
return (
<div>{card}</div>
);
}
});
ReactDOM.render(
<MyClass data={['a', 'b', 'c']} />,
document.getElementById('test')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="test"></div>
Also you should look into using or learning es6, which will clean up your code considerably.

Related

ReactJS onClick not working - nothing happends in the browser and in the system console

I've read a lot of threads about this problem, but still I can't fix it.
/** #jsx React.DOM */
var React = require('react/addons');
var SegmentComponent = React.createClass({
handleThatEvent: function (e)
{
console.log('clicked');
},
render: function ()
{
const styles = {
left: this.props.leftPercent + '%',
width: this.props.widthPercent + '%'
};
if (this.props.color !== undefined)
{
styles.backgroundColor = this.props.color;
}
return (
<span onClick={this.handleThatEvent()} style={styles} className="track-notation"></span>
)
}
});
module.exports = SegmentComponent;
When I click on span nothing happends. I'm new in ReactJS, so maybe I missed an obvious thing.
There is not a "clicked" text in the web browser console and in the system console (Terminal).
EDIT:
I tried with
onClick={this.handleThatEvent.bind(this)}
and
{() => this.handleThatEvent()}
and is still nothing.
Also in HTML there isn't onClick attribute in span element:
<span style="left:10%;width:10%;" class="track-notation" data-reactid=".rru3h8zkm2.1:0.0.2.0"></span>
onClick={this.handleThatEvent()}
replace with
onClick={this.handleThatEvent}
Careful you've passed this.handleThatEvent() into onClick event, and executed it there, you need to pass only the function this.handleThatEvent on onClick will execute it... see:
const SegmentComponent = React.createClass({
handleThatEvent: function (e) {
console.log('clicked');
},
render: function () {
const styles = {
left : this.props.leftPercent + '%',
width : this.props.widthPercent + '%'
};
if (this.props.color !== undefined) {
styles.backgroundColor = this.props.color;
}
return (
<span
onClick={this.handleThatEvent}
style={styles}
className="track-notation"
>Click me!
</span>
)
}
});
ReactDOM.render(
<SegmentComponent />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
that's the problem:
onClick={this.handleThatEvent()}
should be like that:
onClick={this.handleThatEvent.bind(this)}
or
onClick={() => this.handleThatEvent()}

React render component multiple times in container with different props?

I am trying to create a reusable "tag" React component, so that users can create tags onclick and see that information displayed in the DOM.
Here's the module:
module.exports = React.createClass({
render: function() {
return (
<div className="language chip" data-lang={this.props.language} data-lang-level={this.props.level}>
{this.props.language} ({this.props.level})
<i className="material-icons">close</i>
</div>
);
}
});
And the onclick call:
var addLanguage = $('a#add-language');
addLanguage.click(function() {
var languageLearning = $('#language-learning');
var levelLearning = $('#language-level');
if (languageLearning != null && levelLearning != null) {
ReactDOM.render(
<LanguageChip
language={languageLearning.val()}
level={levelLearning.val()}
/>,
document.getElementById('language-chips')
);
languageLearning.select2('val', '');
levelLearning.select2('val', '');
}
})
I didn't realise that when using React.DOM, "Any existing DOM elements inside are replaced when first called." This means when adding a second chip, the first is removed. I want users to be able to have multiple chips.
How can I do this?
I don't know if you've got a good reason to not add the form used to create a tag on your component, but it would be much simpler if you could.
Then you just have to add your tags on an array and display them with your LanguageChip component.
I've made an example here: https://jsfiddle.net/snahedis/69z2wepo/28193/
I don't know what's your level of understanding of React so if something isn't clear let me know :)
Edit: the same example inside a preexistent form:
https://jsfiddle.net/snahedis/69z2wepo/28217/
You need to use array to store multiple chips data. Take a look to this simplified example: http://output.jsbin.com/seficu
var LanguageChips = React.createClass({
render: function() {
return (
<div>
{
(this.props.chipsArray).map(function(chip, index) {
return <LanguageChip
key={index}
language={chip.languageLearning}
level={chip.levelLearning}
/>
})
}
</div>
);
}
});
var LanguageChip = React.createClass({
render: function() {
return (
<div className="language chip" data-lang={this.props.language} data-lang-level={this.props.level}>
{this.props.language} ({this.props.level})
<i className="material-icons"></i>
</div>
);
}
});
var chipsArray = [];
document.getElementById('add-language').addEventListener("click", function() {
var languageLearning = 'test1';
var levelLearning = 'test2';
if (languageLearning != null && levelLearning != null) {
chipsArray.push({
languageLearning: languageLearning,
levelLearning: levelLearning
});
ReactDOM.render(
<LanguageChips chipsArray={chipsArray} />,
document.getElementById('language-chips')
);
}
})

Find all components with type in reactjs

I am having trouble finding components by type using scryRenderedComponentsWithType
code:
describe('Layout', function() {
it('test', function(done) {
var Wrapper = React.createClass({
render: function() {
return <div className="testWrapper">Hello <span>Jim<div>hi<ul><li><div><span></span></div></li></ul></div></span></div>;
}
});
var TestWrap = React.createClass({
render() {
return (
<div>
<p>Test this </p>
<Wrapper />
</div>
);
}
})
var renderedTree = TestUtils.renderIntoDocument(<TestWrap />);
var renderedMyComponent = TestUtils.scryRenderedComponentsWithType(renderedTree, 'Wrapper');
console.log(renderedMyComponent.length);
done();
});
});
the output of this test returns an array length of 0. I think I maybe using the function incorrectly but I am not sure where I went wrong.
TestUtils.scryRenderedComponentsWithType(renderedTree, {function})
This requires that the second argument be a function, not a string.
Hence, your variable Wrapper will work, but not the string "Wrapper".

How do I trigger an event on a higher-up element in React?

I'm only a few hours new to React, so I might have missed something obvious. I have an app which looks a bit like this:
var App = React.createClass({
myAction: function(thingId) {
this.setState({currentThing: thingId});
},
render: function() {
return (<ThingsContainer app={this}/>);
}
});
var ThingsContainer = React.createClass({
render: function() {
return (<ThingList app={this.props.app}/>);
}
});
var ThingList = React.createClass({
render: function() {
var self = this;
var thingNodes = this.props.data.map(function (thing) {
return (<Thing thing={thing} app={self.props.app} key={thing.id}></Thing>);
});
return (<div>{thingNodes}</div>);
}
});
var Thing = React.createClass({
performAction: function() {
this.props.app.myAction(this.props.thing.id);
},
render: function() {
return (
<div>
<h2>{this.props.thing.title}</h2>
<button onClick={this.performAction}>pip!</button>
</div>
);
}
});
React.render(<App />, document.getElementById('content'));
I want to trigger an event on the top-level object from a lower-level object. The relevant page doesn't seem to address this situation directly.
In my solution I'm passing down the app object several levels. This doesn't feel right. In Ember I would be able to use a singleton Controller. In Angular I'd probably use a service. In Backbone or jQuery I'd use an event.
I don't know how much magic wiring of this sort to expect from React.
Is my above solution, which involves explicit wiring between components, even across several edges, the right approach?
I would just pass down the function instead of the whole object:
var App = React.createClass({
myAction: function(thingId) {
this.setState({currentThing: thingId});
},
render: function() {
return (<ThingsContainer myAction={this.myAction}/>);
}
});
var ThingsContainer = React.createClass({
render: function() {
return (<ThingList myAction={this.props.myAction}/>);
}
});
var ThingList = React.createClass({
render: function() {
var self = this;
var thingNodes = this.props.data.map(function (thing) {
return (<Thing thing={thing} myAction={this.props.myAction} key={thing.id}></Thing>);
});
return (<div>{thingNodes}</div>);
}
});
var Thing = React.createClass({
performAction: function() {
this.props.myAction(this.props.thing.id);
},
render: function() {
return (
<div>
<h2>{this.props.thing.title}</h2>
<button onClick={this.performAction}>pip!</button>
</div>
);
}
});
React.render(<App />, document.getElementById('content'));
other than that I don't see anything wrong with your approach, it does feel a bit strange at first but the nice thing about it is that the parent element is always responsible for directly modifying state, and it's very easy to debug issues like this since there is a very clear and concise 'flow'.

Custom image toggle button in ReactJS

I have this ReactJS code to show a custom image button that toggles between 2 different images for ON and OFF state. Is there a simpler way to do this? I was hoping CSS might be less lines of code, but wasn't able to find a simple example.
The code below passes state up from <MyIconButton> to <MyPartyCatButton> then to <MyHomeView>. My app will have 4 of these custom buttons on the home screen, which is why I factored out <MyIconButton>.
btw - this is for a mobile App and I read (and noticed this myself) it's really slow using checkboxes on mobile browsers; that's why I chose to try this without using checkboxes.
ReactJS code
var MyIconButton = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
console.log("INSIDE: MyIconButton handleSubmit");
// Change button's state ON/OFF,
// then sends state up the food chain via
// this.props.updateFilter( b_buttonOn ).
var b_buttonOn = false;
if (this.props.pressed === true) {
b_buttonOn = false;
}
else {
b_buttonOn = true;
}
// updateFilter is a 'pointer' to a method in the calling React component.
this.props.updateFilter( b_buttonOn );
},
render: function() {
// Show On or Off image.
// ** I could use ? : inside the JSX/HTML but prefer long form to make it explicitly obvious.
var buttonImg = "";
if (this.props.pressed === true) {
buttonImg = this.props.onpic;
}
else {
buttonImg = this.props.offpic;
}
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type="image" src={buttonImg}></input>
</form>
</div>
);
}
});
// <MyPartyCatButton> Doesn't have it's own state,
// passes state of <MyIconButton>
// straight through to <MyHomeView>.
var MyPartyCatButton = React.createClass({
render: function() {
return (
<MyIconButton pressed={this.props.pressed} updateFilter={this.props.updateFilter} onpic="static/images/icon1.jpeg" offpic="static/images/off-icon.jpg"/>
);
}
});
//
// Main App view
var MyHomeView = React.createClass({
getInitialState: function() {
// This is where I'll eventually get data from the server.
return {
b_MyPartyCat: true
};
},
updatePartyCategory: function(value) {
// Eventually will write value to the server.
this.setState( {b_MyPartyCat: value} );
console.log("INSIDE: MyHomeView() updatePartyCategory() " + this.state.b_MyPartyCat );
},
render: function() {
return (
<div>
<MyPartyCatButton pressed={this.state.b_MyPartyCat} updateFilter={this.updatePartyCategory}/>
</div>
// Eventually will have 3 other categories i.e. Books, Skateboards, Trees !
);
}
});
if you update the coponent 'pressed' prop dynamically (like you did), simply
var MyIconButton= React.createClass({
render: function(){
var pic= this.props.pressed? this.props.onpic : this.props.offpic
return <img
src={pic}
onClick={this.props.tuggleSelection} //updateFilter is wierd name
/>
}
})
(EDIT: this way, on MyPartyCatButton component, you can pass function to handle 'tuggleSelection' event. event function argument is an event object, but you have the button state allready in the wrapper state (the old one, so you should invert it). your code will be something like that:
render: function(){
return <MyIconButton pressed={this.state.PartyCatPressed} tuggleSelection={this.updatePartyCategory} />
}
updatePartyCategory: function(e){
this.setState(
{PartyCatPressed: !this.state.PartyCatPressed} //this invert PartyCatPressed value
);
console.log("INSIDE: MyHomeView() updatePartyCategory() " + this.state.b_MyPartyCat )
}
)
but if you don't, use prop for defult value:
var MyIconButton= React.createClass({
getInitialState: function(){
return {pressed: this.props.defultPressed}
},
handleClick: function(){
this.setState({pressed: !this.state.pressed})
},
render: function(){
var pic= this.state.pressed? this.props.onpic : this.props.offpic
return <img
src={pic}
onClick={this.handleClick}
/>
}
})

Categories

Resources