I am fairly new to React and was wondering if anybody could give me an insight on a problem I am stuck with.
Right now I have a parent(Hello.js) component and two children(Mixer.js and renderCont.js) at the same level.
I am trying to render a list in the Mixer.js and display its corresponding objects in the Hello.js through by passing the values into RenderCont.js. I've gotten to a point where nothing is displayed before I click on any of the list to pass on a object.
From here is where I am stuck: I want the first object of the list to be displayed as a default, at the same time bold the first in the list. And then execute the as I have below.
This is my first time posting a question on stackoverflow so I'm not sure if my question makes sense with the attached codes but I will greatly appreciate any kind of support.
Parent Hello.js:
import React, { Component } from 'react';
import RenderCont from './renderCont.js';
import Mixer from './Mixer';
class Hello extends Component{
constructor(props) {
super(props);
this.state = {
items: [{
id: 0,
name: "First",
background: "white"
}, {
id: 1,
name: "Second",
background: "yellow"
}, {
id: 2,
name: "Third",
background: "blue"
}],
selectedItem: 0
}
this.handle = this.handle.bind(this)
}
handle(value) {
// console.log(this.state.selectedItem);
this.setState({
selectedItem: value
})
}
render() {
const list = this.state.items.map((item) => {
return(item);
})
return (
<div>
<Mixer item={list} onClick={this.handle} selected={this.state.selectedItem}/>
<ul id = "todo" >
<RenderCont item={this.state.selectedItem}/>
</ul>
</div>
)
}
}
export default Hello;
Mixer.js Child1:
import React, { Component } from 'react';
class Mixer extends Component{
constructor(props) {
super(props);
this.state = {
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(item){
this.props.onClick(item);
}
renderTodos(propItems) {
return (
<div>
{propItems.map((item) => (
<li className={this.props.selected === item ? 'media clicked' : 'media'}
key={item.id} onClick = {() => this.handleClick(item)}>
{item.name}
</li>
))}
</div>
)
}
render() {
return (
<div className="yoyoyo">
{this.renderTodos(this.props.item)}
</div>
)
}
}
export default Mixer;
Second Child Comp renderCont.js :
import React, { Component } from 'react';
class RenderCont extends Component{
constructor(props) {
super(props);
}
renderBox(item){
return(
<div style={{color:item.background}}>
{item.id}
{item.name}
</div>
)
}
render() {
return (
<div className="yoyo">
{this.renderBox(this.props.item)}
</div>
)
}
}
export default RenderCont;
and the CSS:
.yoyo{
left: 500px;
background-color:red;
width:500px;
height:500px;
}
.media{
color: black;
}
.clicked{
font-weight: 900;
}
.yoyoyo{
background-color:lightblue;
width:200px;
height:200px;
}
I think the problem is some mismatch between the initial and eventual value of this.props.selected in Mixer.js. You initially set this.state.selectedItem = 0, and this is what is initially passed as the selected prop to Mixer. But the test you apply in that component is
this.props.selected === item ?
While there is one item.id that === 0, there is never an item that === 0. So no items are highlighted at first. But then, once an item is clicked and selectedItem is actually set to an item, the entry is made bold.
So it looks like you need to either make your initial selection equal to the item.id === 0 reference, or consistently refer to items within your components by their id's.
I'm new to ReactJS and trying to make a small web application.
I have a list of items to put in a sidebar, and I want each item to give back a status tu the sidebar when clicked (so that I can style the active link accordingly).
import React, {Component} from 'react';
import SideBarItem from "./SideBarItem";
const items = {
'DASHBOARD' : 'home',
'Utenti': 'user',
'Corsi' : 'education',
'Logistica' : 'check',
'Comunicazioni': 'bullhorn'
};
const listItems = Object.entries(items).map(([key,value])=>{
return <SideBarItem
onClick={this.changeState(key)} active={this.state.active == key ? 'active' : ''}
title={key}
glyph={'glyphicon glyphicon-' + value.toString()}/>
});
class SideBar extends Component {
constructor(props) {
super(props);
this.state = {active: 'DASHBOARD'};
}
changeState (row) {
this.setState({
active: row
});
}
render() {
return (
<div id = "sidebar" className="col-sm-3 col-md-2 sidebar paper-depth-1">
<ul className = 'nav nav-sidebar'>
{listItems}
</ul>
</div>
);
}
}
export default SideBar;
But this code is returnig the following error:
TypeError: _this.changeState is not a function
I understand that there's something wrong in calling a component function from an outside variable, but I don't get how can I make this work in any other way.
If you create the list of items in render(), the this scope will be the component instance, as you need it to be.
class SideBar extends Component {
constructor(props) {
super(props);
this.state = {active: 'DASHBOARD'};
}
changeState(row) {
this.setState({
active: row
});
}
render() {
return (
<div id="sidebar" className="col-sm-3 col-md-2 sidebar paper-depth-1">
<ul className="nav nav-sidebar">
{Object.entries(items).map(([key,value]) =>
<SideBarItem
onClick={() => this.changeState(key)}
active={this.state.active == key ? 'active' : ''}
title={key}
glyph={'glyphicon glyphicon-' + value.toString()}
/>
)}
</ul>
</div>
);
}
}
Below is my code...
<ul className="no-style board__list">
{Object.keys(today.books).map(function(id) {
var refBook = today.books[id][0];
return (
<li key={refBook._id} className="board__list-item">
<div className="container flexrow">
<div className="flexrow__fit-2">{refBook.book_no}</div>
<div className="flexrow__org">
<span className="board__icon-wrap">
{refBook.memo
? (<i className="fa fa-flag" style={{color:"#F9AB9F"}}></i>)
: null
}
</span>
{refBooking.memo
? (<div className="memo_dialog">{refBook.memo}</div>)
: null
}
</div>
</div>
</li>
);
})}
</ul>
I have a object books array and I create a fa-flag icon for each book.
What I want is to show different memo dialog when mouse hover on each flag icon.
I know how to do it with query but how can I do this in react way not using jquery?
I'm not sure what are you trying to achieve but this example might be useful for you
class Book extends React.Component {
constructor(props){
super(props);
this.handleOver = this.handleOver.bind(this);
}
handleOver(name){
this.props.over(this.props.name)
}
render(){
return <div onMouseOver={this.handleOver}>{this.props.name}</div>
}
}
class BookList extends React.Component {
constructor(props){
super(props);
this.mouseOver = this.mouseOver.bind(this);
this.state = {
books: ['hello', 'amazing', 'world'],
memo: ''
}
}
mouseOver(name){
this.setState({memo: name})
}
render(){
const bookList = this.state.books.map((book, index)=>{
return <Book key={index} name={book} over={this.mouseOver}/>
});
return <div>
{bookList}
<hr/>
<div>{this.state.memo}</div>
</div>
}
}
React.render(<BookList />, document.getElementById('container'));
Also fiddle example.
I hope it will help you. Thanks
I suggest you to use isHovered state variable, to store hover state.
We are displaying some component(in your case it would be dialog box), if isHovered is true and hide it when this variable is false.
When we will hover on link element, we will trigger handleEnter function to set isHovered variable to true.
Similarly, when we are moving cursor out of link element, we are triggering handleLeave function to set isHovered variable to false.
Example:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
isHovered: false,
};
}
handleEnter() {
this.setState({
isHovered: true
});
}
handleLeave() {
this.setState({
isHovered: false
});
}
render() {
return (
<div>
<a
onMouseEnter={this.handleEnter.bind(this)}
onMouseLeave={this.handleLeave.bind(this)}
>Link</a>
{this.state.isHovered ? (
<div className="box">A component</div>
) : (
<div />
)}
</div>
);
}
}
Also, you can see demo at CodePen.
I'm having a bit of a head ache trying to figure out the React way of implementing this.
I have a Searches component which houses SearchItems, when an item is clicked among other things I need to set it's state to active to that it gets the correct CSS, I managed to get this working fine but how would I go about removing the active state from the others?
I was thinking that I could pass down a function from the top level component that would take the ID of the search, when clicked it'd zip through SearchItems and change their state to either true/false depending on which ID it was?
Code below!
Top level component:
import React from "react";
import {Link} from "react-router";
import Search from "./Search";
export default class Searches extends React.Component {
constructor(){
super();
this.state = {
searches : [
{
id : "2178348216",
searchName: "searchName1",
matches: "5"
},
{
id : "10293840132",
searchName: "searchName2",
matches: "20"
}
]
};
}
render() {
const { searches } = this.state;
const SearchItems = searches.map((search) => {
return <Search key={search.id} {...search}/>
})
return (
<div> {SearchItems} </div>
);
}
}
Search items component
export default class Search extends React.Component {
constructor() {
super();
// Set the default panel style
this.state = {
panelStyle: { height: '90px', marginBottom: '6px', boxShadow: '' },
selected: false
}
}
isActive(){
return 'row panel panel-success ' + (this.state.selected ? 'active' : 'default');
}
viewNotifications(e){
this.setState({selected: true});
}
render() {
const { id, searchName, matches } = this.props;
const buttonStyle = {
height: '100%',
width: '93px',
backgroundColor: '#FFC600'
}
return (
<div style={this.state.panelStyle} className={this.isActive()}>
<div class="col-xs-10">
<div class="col-xs-7">
Search Name: {searchName}
</div>
<div class="col-xs-7">
Must Have: PHP, MySQL
</div>
<div class="col-xs-7">
Could Have: AngularJS
</div>
</div>
<button type="button" onClick={this.viewNotifications.bind(this)} style={buttonStyle} class="btn btn-default btn-lg"> {matches} </button>
</div>
);
}
}
I think you don't need the state in the child component at all. In fact is a good idea to avoid having state in most components so they are easy to reason and reuse.
I would leave all the state only on the parent component in this case.
TOP Component:
import React from "react";
import Search from "./search";
export default class Searches extends React.Component {
constructor(){
super();
this.state = {
searches : [
{
id : "2178348216",
searchName: "searchName1",
matches: "5"
},
{
id : "10293840132",
searchName: "searchName2",
matches: "20"
}
],
activeElement : null
};
}
_onSearchSelect(searchId) {
this.setState({'activeElement': searchId})
}
render() {
const { searches, activeSearchId } = this.state;
const SearchItems = searches.map((search) => {
return <Search key={search.id} {...search}
isActive={search.id === activeElement}
onSelect={this._onSearchSelect.bind(this)} />
})
return (
<div> {SearchItems} </div>
);
}
}
CHILD Component:
import React from "react";
export default class Search extends React.Component {
_getPanelClassNames() {
const { isActive } = this.props
return 'row panel panel-success ' + (isActive ? 'active' : 'default')
}
_onSelect() {
const { id, onSelect } = this.props;
onSelect(id)
}
render() {
const { searchName, matches } = this.props;
const panelStyle = { height: '90px', marginBottom: '6px', boxShadow: '' }
const buttonStyle = {
height: '100%',
width: '93px',
backgroundColor: '#FFC600'
}
return (
<div style={panelStyle} className={this._getPanelClassNames()}>
<div className="col-xs-4">
Search Name: {searchName}
</div>
<div className="col-xs-3">
Must Have: PHP, MySQL
</div>
<div className="col-xs-3">
Could Have: AngularJS
</div>
<div className="col-xs-2">
<button type="button" onClick={this._onSelect.bind(this)}
style={buttonStyle} className="btn btn-default btn-lg"
>
{matches}
</button>
</div>
</div>
);
}
}
You can also see it running in Plunker: https://plnkr.co/edit/sdWzFedsdFx4MpbOuPJD?p=preview
Ok it turns out this is simpler than I thought and is simply a case of understanding how react works(and not getting confused) .
When you have a top level component you pass it's state via props to children, when you update the state in the top level component it'll pass that down to the children and you can use componentWillReceiveProps to take action.
I added a function to my top level component called updateActiveSearch which simply sets the state of the TOP level component I then passed the activeElement state as a prop to the child Elements along with the function. When a child element calls this function to set itself as active all of them will fire componentWillReceiveProps, they simply just need to check their own ID against the one they've received, if it matches they're active, if it doesn't they're not!
So my top level component now looks like this:
export default class Searches extends React.Component {
constructor(){
super();
this.state = {
searches : [
{
id : "2178348216",
searchName: "searchName1",
matches: "5"
},
{
id : "10293840132",
searchName: "searchName2",
matches: "20"
}
],
activeElement : 0
};
}
// This function gets passed via a prop below
updateActiveSearch(id){
//console.log(id);
this.setState({activeElement : id});
}
render() {
const SearchItems = this.state.searches.map((search) => {
return <Search activeElement={this.state.activeElement} goFunction={this.updateActiveSearch.bind(this)} key={search.id} {...search}/>
})
return (
<div> {SearchItems} </div>
);
}
}
CHILD COMPONENTS
export default class Search extends React.Component {
constructor() {
super();
// Set the default panel style
this.state = {
panelStyle: { height: '90px', marginBottom: '6px', boxShadow: '' },
selected: false
}
}
// This happens right before the props get updated!
componentWillReceiveProps(incomingProps){
if(incomingProps.activeElement == this.props.id){
this.setState({selected: true});
} else {
this.setState({selected: false});
}
}
isActive(){
return 'row panel panel-success ' + (this.state.selected ? 'active' : 'default');
}
viewNotifications(e){
//this.state.panelStyle.boxShadow = '-2px 3px 20px 5px rgba(255,198,0,1)';
this.setState({selected: true});
this.props.goFunction(this.props.id);
}
render() {
const { id, searchName, matches } = this.props;
const buttonStyle = {
height: '100%',
width: '93px',
backgroundColor: '#FFC600'
}
return (
<div style={this.state.panelStyle} className={this.isActive()}>
<div class="col-xs-10">
<div class="col-xs-7">
Search Name: {searchName}
</div>
<div class="col-xs-7">
Must Have: PHP, MySQL
</div>
<div class="col-xs-7">
Could Have: AngularJS
</div>
</div>
<button type="button" onClick={this.viewNotifications.bind(this)} style={buttonStyle} class="btn btn-default btn-lg"> {matches} </button>
</div>
);
}
}
I have
var TestApp = React.createClass({
getComponent: function(){
console.log(this.props);
},
render: function(){
return(
<div>
<ul>
<li onClick={this.getComponent}>Component 1</li>
</ul>
</div>
);
}
});
React.renderComponent(<TestApp />, document.body);
I want to color the background of the clicked list element. How can I do this in React ?
Something like
$('li').on('click', function(){
$(this).css({'background-color': '#ccc'});
});
Why not:
onItemClick: function (event) {
event.currentTarget.style.backgroundColor = '#ccc';
},
render: function() {
return (
<div>
<ul>
<li onClick={this.onItemClick}>Component 1</li>
</ul>
</div>
);
}
And if you want to be more React-ive about it, you might want to set the selected item as state of its containing React component, then reference that state to determine the item's color within render:
onItemClick: function (event) {
this.setState({ selectedItem: event.currentTarget.dataset.id });
//where 'id' = whatever suffix you give the data-* li attribute
},
render: function() {
return (
<div>
<ul>
<li onClick={this.onItemClick} data-id="1" className={this.state.selectedItem == 1 ? "on" : "off"}>Component 1</li>
<li onClick={this.onItemClick} data-id="2" className={this.state.selectedItem == 2 ? "on" : "off"}>Component 2</li>
<li onClick={this.onItemClick} data-id="3" className={this.state.selectedItem == 3 ? "on" : "off"}>Component 3</li>
</ul>
</div>
);
},
You'd want to put those <li>s into a loop, and you need to make the li.on and li.off styles set your background-color.
Two ways I can think of are
var TestApp = React.createClass({
getComponent: function(index) {
$(this.getDOMNode()).find('li:nth-child(' + index + ')').css({
'background-color': '#ccc'
});
},
render: function() {
return (
<div>
<ul>
<li onClick={this.getComponent.bind(this, 1)}>Component 1</li>
<li onClick={this.getComponent.bind(this, 2)}>Component 2</li>
<li onClick={this.getComponent.bind(this, 3)}>Component 3</li>
</ul>
</div>
);
}
});
React.renderComponent(<TestApp /> , document.getElementById('soln1'));
This is my personal favorite.
var ListItem = React.createClass({
getInitialState: function() {
return {
isSelected: false
};
},
handleClick: function() {
this.setState({
isSelected: true
})
},
render: function() {
var isSelected = this.state.isSelected;
var style = {
'background-color': ''
};
if (isSelected) {
style = {
'background-color': '#ccc'
};
}
return (
<li onClick={this.handleClick} style={style}>{this.props.content}</li>
);
}
});
var TestApp2 = React.createClass({
getComponent: function(index) {
$(this.getDOMNode()).find('li:nth-child(' + index + ')').css({
'background-color': '#ccc'
});
},
render: function() {
return (
<div>
<ul>
<ListItem content="Component 1" />
<ListItem content="Component 2" />
<ListItem content="Component 3" />
</ul>
</div>
);
}
});
React.renderComponent(<TestApp2 /> , document.getElementById('soln2'));
Here is a DEMO
I hope this helps.
Here is how you define a react onClick event handler, which was answering the question title... using es6 syntax
import React, { Component } from 'react';
export default class Test extends Component {
handleClick(e) {
e.preventDefault()
console.log(e.target)
}
render() {
return (
<a href='#' onClick={e => this.handleClick(e)}>click me</a>
)
}
}
Use ECMA2015. Arrow functions make "this" a lot more intuitive.
import React from 'react';
class TestApp extends React.Component {
getComponent(e, index) {
$(e.target).css({
'background-color': '#ccc'
});
}
render() {
return (
<div>
<ul>
<li onClick={(e) => this.getComponent(e, 1)}>Component 1</li>
<li onClick={(e) => this.getComponent(e, 2)}>Component 2</li>
<li onClick={(e) => this.getComponent(e, 3)}>Component 3</li>
</ul>
</div>
);
}
});
React.renderComponent(<TestApp /> , document.getElementById('soln1'));`
If you're using ES6, here's some simple example code:
import React from 'wherever_react_is';
class TestApp extends React.Component {
getComponent(event) {
console.log('li item clicked!');
event.currentTarget.style.backgroundColor = '#ccc';
}
render() {
return(
<div>
<ul>
<li onClick={this.getComponent.bind(this)}>Component 1</li>
</ul>
</div>
);
}
}
export default TestApp;
In ES6 class bodies, functions no longer require the 'function' keyword and they don't need to be separated by commas. You can also use the => syntax as well if you wish.
Here's an example with dynamically created elements:
import React from 'wherever_react_is';
class TestApp extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
{name: 'Name 1', id: 123},
{name: 'Name 2', id: 456}
]
}
}
getComponent(event) {
console.log('li item clicked!');
event.currentTarget.style.backgroundColor = '#ccc';
}
render() {
<div>
<ul>
{this.state.data.map(d => {
return(
<li key={d.id} onClick={this.getComponent.bind(this)}>{d.name}</li>
)}
)}
</ul>
</div>
);
}
}
export default TestApp;
Note that each dynamically created element should have a unique reference 'key'.
Furthermore, if you would like to pass the actual data object (rather than the event) into your onClick function, you will need to pass that into your bind. For example:
New onClick function:
getComponent(object) {
console.log(object.name);
}
Passing in the data object:
{this.state.data.map(d => {
return(
<li key={d.id} onClick={this.getComponent.bind(this, d)}>{d.name}</li>
)}
)}
Handling events with React elements is very similar to handling events
on DOM elements. There are some syntactic differences:
React events are named using camelCase, rather than lowercase.
With JSX you pass a function as the event handler, rather than a string.
So as mentioned in React documentation, they quite similar to normal HTML when it comes to Event Handling, but event names in React using camelcase, because they are not really HTML, they are JavaScript, also, you pass the function while we passing function call in a string format for HTML, they are different, but the concepts are pretty similar...
Look at the example below, pay attention to the way event get passed to the function:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
import React from 'react';
class MyComponent extends React.Component {
getComponent(event) {
event.target.style.backgroundColor = '#ccc';
// or you can write
//arguments[0].target.style.backgroundColor = '#ccc';
}
render() {
return(
<div>
<ul>
<li onClick={this.getComponent.bind(this)}>Component 1</li>
</ul>
</div>
);
}
}
export { MyComponent }; // use this to be possible in future imports with {} like: import {MyComponent} from './MyComponent'
export default MyComponent;
class FrontendSkillList extends React.Component {
constructor() {
super();
this.state = { selectedSkill: {} };
}
render() {
return (
<ul>
{this.props.skills.map((skill, i) => (
<li
className={
this.state.selectedSkill.id === skill.id ? "selected" : ""
}
onClick={this.selectSkill.bind(this, skill)}
style={{ cursor: "pointer" }}
key={skill.id}
>
{skill.name}
</li>
))}
</ul>
);
}
selectSkill(selected) {
if (selected.id !== this.state.selectedSkill.id) {
this.setState({ selectedSkill: selected });
} else {
this.setState({ selectedSkill: {} });
}
}
}
const data = [
{ id: "1", name: "HTML5" },
{ id: "2", name: "CSS3" },
{ id: "3", name: "ES6 & ES7" }
];
const element = (
<div>
<h1>Frontend Skill List</h1>
<FrontendSkillList skills={data} />
</div>
);
ReactDOM.render(element, document.getElementById("root"));
.selected {
background-color: rgba(217, 83, 79, 0.8);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
#user544079 Hope this demo can help :) I recommend changing background color by toggling classname.
import React from 'react';
class MyComponent extends React.Component {
getComponent(event) {
event.target.style.backgroundColor = '#ccc';
// or you can write
//arguments[0].target.style.backgroundColor = '#ccc';
}
render() {
return(
<div>
<ul>
<li onClick={this.getComponent.bind(this)}>Component 1</li>
</ul>
</div>
);
}
}
export { MyComponent }; // use this to be possible in future imports with {} like: import {MyComponent} from './MyComponent'
export default MyComponent;
You can make use of the React.createClone method. Create your element, than create a clone of it. During the clone's creation, you can inject props. Inject an onClick : method prop like this
{ onClick : () => this.changeColor(originalElement, index) }
the changeColor method will set the state with the duplicate, allowing you sto set the color in the process.
render()
{
return(
<ul>
{this.state.items.map((val, ind) => {
let item = <li key={ind}>{val}</li>;
let props = {
onClick: () => this.Click(item, ind),
key : ind,
ind
}
let clone = React.cloneElement(item, props, [val]);
return clone;
})}
</ul>
)
}
This is a non-standard (but not so uncommon) React pattern that doesn't use JSX, instead putting everything inline. Also, it's Coffeescript.
The 'React-way' to do this would be with the component's own state:
(c = console.log.bind console)
mock_items: [
{
name: 'item_a'
uid: shortid()
}
{
name: 'item_b'
uid: shortid()
}
{
name: 'item_c'
uid: shortid()
}
]
getInitialState: ->
lighted_item: null
render: ->
div null,
ul null,
for item, idx in #mock_items
uid = item.uid
li
key: uid
onClick: do (idx, uid) =>
(e) =>
# justf to illustrate these are bound in closure by the do lambda,
c idx
c uid
#setState
lighted_item: uid
style:
cursor: 'pointer'
background: do (uid) =>
c #state.lighted_item
c 'and uid', uid
if #state.lighted_item is uid then 'magenta' else 'chartreuse'
# background: 'chartreuse'
item.name
This example works -- I tested it locally.
You can check out this example code exactly at my github.
Originally the env was only local for my own whiteboard r&d purposes but I posted it to Github for this. It may get written over at some point but you can check out the commit from Sept 8, 2016 to see this.
More generally, if you want to see how this CS/no-JSX pattern for React works, check out some recent work here. It's possible I will have time to fully implement a POC for this app idea, the stack for which includes NodeJS, Primus, Redis, & React.