can we attach click handlers to custom child components - reactjs

I was trying to add a click handler to my own child component. In react chrome extension I was able to see the click handler as well.
But the click itself didn't work - wondering what did I miss.
Sample Code:
...
render (
<MySampleComponent onClick={this.handler} />
);
...

MySampleComponent can take whichever props it wants; components don't automatically copy props to their children. If you want to be able to add an onClick handler to MySampleComponent, then you can support this in the definition of that component:
var MySampleComponent = React.createClass({
render: function() {
return <div onClick={this.props.onClick}>...</div>;
}
});

You can add the handler from the samecomponent or call it through props.
Below code looks for onClick param in props. If nothing is passed, then
it goes for default handler in the component(clickHandler).
var MySampleComponent = React.createClass({
clickHandler: function(){
// write your logic
},
render: function() {
return <div onClick={this.props.onClick || this.clickHandler}>...</div>;
}
});
and while using this in another component use it as below
...........
handler: function() {
// write your logic
},
render {
var self = this;
return (<MySampleComponent onClick={self.handler} />);
}
......

Related

Understanding React props

Looking at Facebook's react example here, I found this code showing how to use mixins to set intervals. I am confused as to what is happening with this.intervals. I understand that state holds render-altering data, and props handle data handed down from a parent component, ideally. I would have used this.props.intervals instead, but what is the difference between the two?
var SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.forEach(clearInterval);
}
};
var TickTock = React.createClass({
mixins: [SetIntervalMixin], // Use the mixin
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
this.setInterval(this.tick, 1000); // Call a method on the mixin
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
React has been running for {this.state.seconds} seconds.
</p>
);
}
});
ReactDOM.render(
<TickTock />,
document.getElementById('example')
);
When you use props, you know for 100% certainty the value should will be coming from it's immediate parent component (as a property).
When you see state, you know the value is being born/created within that component it's self.
The key, when state changes, every child below will render if any of their received props change.
Your Mixin is not a normal React class. It is simply an object, so this in the case of this.interval, is a reference to the scope of the object in which the method is being executed - TickTock.

How to bind event handler function dynamically in React

All:
I am pretty new to React, say I have a very simple case:
var React = require("react");
var ReactDOM = require("react-dom");
var Todo = React.createClass({
render: function() {
return (<div>Hello there
<button id="switch_func">Switch</button>
</div>);
}
});
ReactDOM.render(<Todo />, document.getElementById("div1"));
What I am trying to bind is:
There are multiple handler functions, each time when that button switch_func gets clicked, it will randomly choose another handlers and bind to itself.
But I do not know how to bind it like in AngularJS or jQuery, cos I am not sure if I can do same thing to the virtual DOM:
$("button#switch_func").on("click", function(){
$(this).off("click");
$(this).on("click", anotherHandler);
});
To bind functions you can use onClick
Simply put
<button onClick={this.handleClick}>Switch</button>
And handle the click event on the component's function:
var Todo = React.createClass({
handleClick: function(){
//put your function here!
},
//other functions in your component (e.g. render, getInitialState, etc)
});

ReactJS: best practice access input values when creating forms

I've been playing a bit with ReactJS and am really enjoying the framework.
I'm also trying to follow the rule of creating components that are stateless where possible.
I have a Settings component that includes a child SettingsForm and a SettingsWidget.
Settings holds all the states, and only pass it as props to the form and widget.
This works (and scales) well because when the state in Settings is updated, it propagates to all child components.
var Settings = React.createClass({
getInitialState: function() {
settings: {}
}
})
What I am not 100% sure on is the best practice when accessing input values on SettingsForm to pass it on to the parent component.
I know I can use refs and also two-way binding to accomplish this, but neither feel very "ReactJS-like".
Is there a better of way accomplishing this that I am unaware of? For the sake of completeness, I've included the relevant code in my SettingsForm component below
var SettingsForm = React.createClass({
getInitialState: function() {
return {
changed: false
}
},
handleChange: function(event) {
this.setState({changed: true})
this.props.handleChange(
this.refs.emailInputFieldRef.getDOMNode().value,
this.refs.firstNameInputFieldRef.getDOMNode().value
)
},
handleSubmit: function(event) {
event.preventDefault();
// Access and pass on input values to parent callback so state is updated
this.props.handleUpdate(
this.refs.emailInputFieldRef.getDOMNode().value,
this.refs.firstNameInputFieldRef.getDOMNode().value
)
this.setState(this.getInitialState());
},
...
}
For now there is a Mixin you can use to link the input values to the state, called LinkedStateMixin that is exactly what you are looking for...
var WithLink = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
return <input type="text" valueLink={this.linkState('message')} />;
}
});
Then all you have to do is modify your handler functions on the parent component to take your inputs as variables, and pass that function down to the child component as a prop. When you want to handle the form, call that function in the props and send the state (bound with from the Mixin) as the variables.
React Docs - React Link

Parent displaying the title and other metadata of a child

Let's say I have a main component which provides common elements for all views in my app:
var Main = React.createClass({
render: function() {
return (
<div id="main">
<MenuBar title={this.state.title} icon={this.state.title} />
<div id="view">{React.Children.only(this.props.children)}</div>
</div>
);
}
});
Then I could use it like this:
<Main>{router.routeComponent(path)}</Main>
Now, I would like the title property (and possibly other "meta" information about the child) of the menu bar be set by the child view in this case. My current idea for this is to have child views expose a .getMetadata() method and a onMetadataChanged={...} property and then have the child return an object like { title: "Foobar", icon: "images/foobar.png" } from the getMetadata() method.
A second option would be to repeat the Main component for every view like this:
var SomeView = React.createClass({
render: function() {
return (
<Main title="Some view" icon="images/foobar.png">
{/* view content here */}
</Main>
);
}
});
However, the disadvantage of this, if I understand correctly, is that the performance will be worse when switching view since React will not try to merge the DOM tree if the SomeView component changes to an entirely different component (i.e. SomeOtherView). This would mean that all of DOM nodes of Main would have to be recreated.
What would the idiomatic/best way be to do this in React?
The simplest solution would be an event emitter. You could also use flux if you're already using it.
var emitter = new (require('events').EventEmitter); // or from http://wzrd.in/standalone/events
var Main = React.createClass({
// apply the metadata to state when the event is emitted
componentDidMount: function(){
emitter.on('site-metadata', this.handleMetadata);
},
handleMetadata: function(meta){
this.setState({title: meta.title, icon: meta.icon});
},
// in willUnmount remove the listener
render: function() {
// ...
}
});
router.provideSiteMetadata = function(meta){
Object.assign(router.meta, meta);
emitter.emit('site-metadata', router.meta);
};
router.meta = {title: '', icon: null};
You then call router.provideSiteMetadata, and any components interested in this metadata will be notified, and can apply it to state.

AngularJS app inside ReactJS component?

Is it possible to create an Angular app inside a react component?
Something like:
React.createClass({
render: function() {
return <div ng-app>...</div>;
}
});
This is completely backwards, but will only have to be a temporary solution. I'm assuming I could do something like the code above, and add the angular bootstrapping to the componentDidMount lifecycle method.
Has anyone successfully done this?
Thanks.
It would look something like this:
componentDidMount: function(){
this._angularEl = document.createElement("div");
this._angularEl.innerHTML = angularTemplatHTMLString;
this._angularEl.setAttribute("ng-app", "");
this.getDOMNode().appendChild(this._angularEl);
// bind angular to this._angularEl
},
componentWillUnmount: function(){
// unbind angular from this._angularEl
this.getDOMNode().removeChild(this._angularEl);
delete this._angularEl;
},
render: function(){
return <div></div>
}
You could either use this for each component, or create a function which returns a mixin.
function makeAngularMixin(template){
return { /* above code except for render */ }
}
or have a component which allows passing an angular template via props.

Resources