React dynamic events - javascript

I have difficulties to attach dynamic events to my react components. I have the following components:
var ListItem = React.createClass({
render: function() {
return (
<li className="selector" >
<div className="column">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<div>{this.props.children}</div>
</div>
</li>
);
}
});
var ListBox = React.createClass({
mixins : [MyMixin],
render : function() {
this.nodes = this.props.data.map(function(item) {
return <ListItem author={item.author}>{item.text}</ListItem>;
});
return (
<ul id="columns">
{this.nodes}
</ul>
);
}
});
As you see the ListItem has className set to "selector". Base on this "selector" I want to query nodes and attach dynamically events in the MyMixin.
React.renderComponent(
<ListBox data={data} selector="li.selector" />,
document.getElementById('example')
);
Maybe my idea is all wrong as I'm fairy new to React.
Regards

You should listen to events directly on the ListItem component. React doesn't want you to think about attaching listeners later.
var ListItem = React.createClass({
handleClick: function(event) {
// Handle ListItem click
},
handleDoubleClick: function(event) {
// Handle ListItem double click
},
render: function() {
return (
<li className="selector"
onClick={this.handleClick}
onDoubleClick={this.handleDoubleClick}>
<div className="column">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<div>{this.props.children}</div>
</div>
</li>
);
}
});
React expects the attributes to exactly match the event name. You can check out the full list of supported events to make sure you use the right names.

Related

How to use the condition map function in ReactJS?

I am trying to display bootstrap carousel via ajax call using react js. Ajax receives json data consisting image name, content title and some meta information of per slide what I want to inject in DOM. So, I use the map function to generate all slides. My problem is, for the first slide I want to add a class active. But I do not know how to use condition in map().
In React, I have written: (in SliderWidget class, I have written a comment actually where I should use active class conditionally)
var HomeCarousel = React.createClass({
getInitialState: function() {
return {
data: []
}
},
componentDidMount: function() {
$.get("/api/slider", function(result) {
this.setState({
data: result
});
}.bind(this));
},
render: function() {
return (
<div id={"myCarousel"} className={"carousel slide"} data-ride="carousel">
{this.state.data.map((slider, i) => <SliderWidget key = {i} data = {slider} />)}
</div>
);
}
});
class SliderWidget extends React.Component {
render() {
return (
<div className={"item active"}> // here I want to use active class for the first slide
<img className={"first-slide"} src="images/pexels.jpeg" alt="First slide" />
<div className={"container"}>
<div className={"carousel-caption"}>
<h3>Research Indicates Breakfast is the Most Important Meal</h3>
<p><a className={"btn btn-primary"} href="#" role="button">Find Out More</a></p>
</div>
</div>
</div>
);
}
}
ReactDOM.render(
<HomeCarousel />, document.getElementById('react-home-carousel')
);
The i in the map callback is the loop index, so pass a property accordingly:
this.state.data.map( (slider, i) =>
<SliderWidget key={i} data={slider} active={i===0} />
)
Then in SliderWidget:
render() {
return (
<div className={"item" + this.props.active ? ' active' : ''}>...
)
}
Using classnames will make your life even easier.

Render JSX element based on condition

So I have a simple component within a web app I have been working on and I was wondering if there is a way I could render an element within this component based on the value of this.props.item.
here is my JSX:
var React = require("react"); var actions = require("../actions/SchoolActions");
module.exports = React.createClass({
deleteSchool: function(e){
e.preventDefault();
actions.deleteSchool(this.props.info);
},
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
<div className="panel-body">{this.props.info.tagline}</div>
</div>
)
} })
I wanted to be able to do something like this:
render:function(){
return(
code blah blah...
if (this.props.info = "nothing"){
<div className="panel-body">{this.props.info.tagline}</div>
}
...code blah blah
But I cannot write javascript withing the render function itself. Does anyone know how I could do this? Any help or advice is appreciated, thank you in advance.
You can use conditionally render using if and return the appropriate jsx
render(){
if(something){
return(<MyJsx1/>)
}else{
return(<MyJsx2/>)
}
}
You can chaage your component to:
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
{this.props.info = "nothing"?
(<div className="panel-body">{this.props.info.tagline}</div>)
:null}
</div>
)
} })
https://facebook.github.io/react/docs/conditional-rendering.html
Single line example
{(this.state.hello) ? <div>Hello</div> : <div>Goodbye</div>}
or
{(this.state.hello) ? <div>Hello</div> : false}
I often create an explicit function to to this, to avoid clutter in the main render:
var ChildComponent = React.createClass({
render: function () {
return (<p>I am the child component</p>)
}
});
var RootComponent = React.createClass({
renderChild: function () {
if (this.props.showChild === 'true') {
return (<ChildComponent />);
}
return null;
},
render: function () {
return(
<div>
{ this.renderChild() }
<p>Hello World!</p>
</div>
)
}
});
http://reactkungfu.com/2016/11/dynamic-jsx-tags/
For many React developers using JSX it is not clear how to make a
dynamic JSX tag. Meaning that instead of hardcoding whether it is
input or textarea or div or span (or anything else) we would like to
keep it in a variable.

Checkbox keeps state across components in React JS

I'm new in React JS, but I read about <input> that you have to save actual state in onChange like described here: React DOC - Forms
I have a list with a checkbox and I applied same behavior here in CampaignsRow
var campaignsData = [{Name: "First"}, {Name: "Second"}, {Name: "Third"}];
var CampaignsRow = React.createClass({
getInitialState: function() {
return {checked: false};
},
checkedChange: function (e) {
this.setState({checked: e.target.checked});
},
render: function() {
console.log(this.props.data.Name, this.state.checked);
return (
<div className="row">
<div className="cell checkbox">
<input type="checkbox" checked={this.state.checked} onChange={this.checkedChange}/>
</div>
<div className="cell campaignName">{this.props.data.Name}</div>
</div>
);
}
});
var CampaignsTable = React.createClass({
render: function() {
var rows = this.props.campaigns.map(function(campaign) {
return (
<CampaignsRow data={campaign}/>
);
});
return <div className="table">
<div className="row header">
<div className="cell checkbox"><input type="checkbox"/></div>
<div className="cell campaignName">Name</div>
</div>
{rows}
</div>
}
});
ReactDOM.render(<CampaignsTable campaigns={campaignsData} /> ,document.getElementById('reactContainer'));
My problem is, if I check the checkbox at the campaign with name First and then I remove first item by campaignsData.shift() (to simulate downloading new data from Server) and then render again, checkbox at Second campaign is checked.
What is the purpose of this.state when it is not attached to the instance. Render works fine, because in the console is printed Second true, so this.state.checked was moved from First to Second campaign.
You should add unique key property to multiple components, so that React can keep track of identities:
var rows = this.props.campaigns.map(function(campaign) {
return (
<CampaignsRow key={campaign.name} data={campaign}/>
);
});

react state bind from child to parent element

I am new to reactJS
I have an JSON array which consists of task. I have rendered the the array to 2 ul list. One has completed tasks and the other has uncompleted tasks. If i click on the task the status is changing but it is not updated in other element. However if I enter some text in the input state is set to other elements. Why the state is not set immediately when I click on task?
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/JSXTransformer.js"></script>
<body>
<div id="todo">
</div>
<script type="text/jsx">
var TodoList = React.createClass({
clickHandle: function(index) {
this.props.items[index].completed=!this.props.items[index].completed;
console.log(this.props);
this.setState({items: this.props.items});
},
render: function() {
var createItem = function(itemText, index) {
if(itemText.completed===this.props.completed)
return <li key={index} onClick={this.clickHandle.bind(this,index)}>{itemText.text}</li>;
};
return <ul>{this.props.items.map(createItem, this)}</ul>;
}
});
var TodoApp = React.createClass({
getInitialState: function() {
return {items: [{"text":"1true","completed":true},{"text":"2true","completed":true},{"text":"1false","completed":false}], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
if(this.state.text!=''){
this.state.items.push({"text":this.state.text,"completed":false});
var nextText = '';
this.setState({items:this.state.items,text: nextText});
}
else{
alert("Enter some text!");
}
},
render: function() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} completed={false}/>
<TodoList items={this.state.items} completed={true}/>
<form onSubmit={this.handleSubmit}>
<input onChange={this.onChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
});
React.render(<TodoApp />, document.getElementById('todo'));
</script>
JSFiddle
This is happening because the parent component, TodoApp which renders the two lists does not know that something has changed in one of the them. For this the child component should notify the parent component about it.
Add a onStatusUpdate attribute to TodoList like this
<TodoList items={this.state.items} completed={false} onStatusUpdate={this.update}/>
This is how the update method can be defined
update: function(items){
this.setState({items: items});
}
In the click handler of child component do something like this
clickHandle: function(index {
this.props.items[index].completed=!this.props.items[index].completed;
this.props.onStatusUpdate(this.props.items); // <-- this triggers the onStatusUpdate attribute defined in TodoList component
},
Here is an updated demo https://jsfiddle.net/dhirajbodicherla/aqqcg1sa/2/`

ReactJs - Why wont child event change state of parent?

I have a created a menu component in reactjs. As you can see, the parent component has a method called "handleClick which toggles the "open state" of the menu, opening and closing it accordingly.
Now, I am trying to pass a click event from the child component "MenuItem" (which is a link in the menu) to the parent "Menu" component so that when one of the menu items is clicked the menu closes.
I have tried to do this in a number of ways. At the moment, I have bound the click event of each "MenuItem" in "MenuList" (the list of MenuItems) to a prop called "whenClicked" and then bound "whenClicked" to the "handleClick" method of "Menu".
The problem is that this seems to have no effect on "Menu". Neither the React tool in Chrome, nor the regular dev console are giving me any errors but the menu does not close when I click one of the MenuItems. The React tool in Chrome allows me to view the virtual DOM and I can see that all of the onClick functions are defined.
Below is the code. As you can see, I am using the same methodology to pass a click event from a different component ("MenuToggle") to "Menu". Oddly enough this works fine and clicking on the toggle button changes the state of "Menu" successfully and opens and closes the menu. I am using the "react-scroll" module for "MenuItem" so maybe that is the issue. Any light anyone can shed on this would be helpful and I would love to know what I am doing incorrectly!
var Menu = React.createClass({
getInitialState: function() {
return {open: false, mobi: false}
},
handleClick: function() {
this.setState({open: !this.state.open})
},
closeOnMobiScroll: function() {
/*
if(this.state.mobi === false) {
this.setState({open: false})
}
*/
},
updateDimensions: function() {
$(window).width() >= 767 ? this.setState({mobi: true}) : this.setState({mobi: false});
},
componentWillMount: function() {
this.updateDimensions();
},
componentDidMount: function() {
$(window).on("resize", this.updateDimensions);
},
componentWillUnmount: function() {
$(window).on("resize", this.updateDimensions);
},
render: function() {
return (
<div id="menu" className={(this.state.open ? 'open' : '')} >
<div id="menu-inner-wrap">
<MenuTitle />
<MenuToggle whenClicked={this.handleClick}/>
<MenuList whenClicked={this.handleClick}/>
</div>
</div>
)
}
});
module.exports = Menu;
var MenuItem = React.createClass({
render: function() {
return (
<li className="menu-link">
<Link to={this.props.menuLink} spy={true} smooth={true} duration={500}>
<i className={this.props.icon}></i>
<span className="menu-link-text">{this.props.menuTitle}</span>
</Link>
</li>
);
}
});
var MenuList = React.createClass({
getInitialState: function() {
return {data: []}
},
componentWillMount: function() {
$.ajax({
url: 'http://10.0.0.97:8888/public-code/React.cv/data/data.json',
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, error) {
var err = JSON.parse(xhr.responseText);
console.log(err.Message);
}
});
},
render: function() {
var list = this.state.data.map(function(menuItemProps) {
return <MenuItem onClick={this.props.whenClicked} {...menuItemProps} key={menuItemProps.id} />
}.bind(this));
return (
<ul id="menu-list">
{list}
</ul>
)
}
});
It seems like you still need to bind the onClick to something that the DOM will handle. Adding an onClick attribute to MenuItem allows you to have a prop inside MenuItem, but you still need to bind it:
var MenuItem = React.createClass({
render: function() {
return (
<li className="menu-link" onClick={this.props.onClick}>
<Link to={this.props.menuLink} spy={true} smooth={true} duration={500}>
<i className={this.props.icon}></i>
<span className="menu-link-text">{this.props.menuTitle}</span>
</Link>
</li>
);
}
});
}
In the above example, onClick is added to the li:
<li className="menu-link" onClick={this.props.onClick}>
The best example in the documentation of behaviour like this is in Expose Component Functions.
In that example you can see that the Todo child component finally binds to div and then bubbles up in a similar way:
var Todo = React.createClass({
render: function() {
return <div onClick={this.props.onClick}>{this.props.title}</div>;
},
//this component will be accessed by the parent through the `ref` attribute
animate: function() {
console.log('Pretend %s is animating', this.props.title);
}
});

Categories

Resources