React JS removeEventListener not firing - javascript

I have two functions with one containing addEventListener("click") and the other to remove
show() {
console.log("SHOW FUNCTION")
this.setState({
listVisible: true
})
document.addEventListener("click", this.hide.bind(this));
}
hide() {
console.log("HIDE FUNCTION")
this.setState({
listVisible: false
})
document.removeEventListener("click", this.hide.bind(this));
}
On initial click, show() is fired, state is updated as expected and once the second click is made hide() is fired and all is well.
When I click again ( third click ) my console.logs list show() first and then two logs for hide() thus setting my state back to false when it should be true, just like the first sequence.
I'm unsure as to why this is happening, it's almost as if the removeEventListener isn't firing. Could also be wrong context of "this"?
Here is my component code:
renderListItems() {
const items = [];
for (var i = 0; i < this.props.list.length; i++) {
const item = this.props.list[i];
items.push(<div className="option" onClick={() => this.select(item)}>
<span>{item.name}</span>
<i className="fa fa-check"></i>
</div>);
}
return items;
}
render() {
console.log("give me", this.state.listVisible)
return (
<div className={"dropdown-container" + (this.state.listVisible ? " show" : "")}>
<div className={"dropdown-display" + (this.state.listVisible ? " clicked": "")} onClick={() => this.show()}>
<span>
{this.state.selected.name}
</span>
<i className="fa fa-angle-down"></i>
</div>
<div className="dropdown-list">
<div>
{this.renderListItems()}
</div>
</div>
</div>
)
}

Every time you call .bind it is creating a new function. You should create the bound function once when the component is created so that the removeEventListener can find the function.
You can bind class methods in ES6:
hide = () => {
}
Or do it in your constructor:
constructor(...args) {
super(...args);
this.hide = this.hide.bind(this);
}
Then your event listener can simply refer to the already bound function this.hide.

I found a solution - to remove the hide function, remove all binds and update state within the select function.
import React, {Component} from 'react'
import classNames from 'classnames';
import './style.scss'
export default class FormCustomSelect extends Component {
constructor(props) {
super(props);
this.state = {
listVisible: false,
display: "",
selected: this.props.selected
}
}
select(item) {
this.setState({
selected: item,
listVisible: false
})
}
show() {
this.setState({
listVisible: true
})
}
renderListItems() {
const items = [];
for (var i = 0; i < this.props.list.length; i++) {
const item = this.props.list[i];
items.push(<div className="option" onClick={() => this.select(item)}>
<span>{item.name}</span>
<i className="fa fa-check"></i>
</div>);
}
return items;
}
render() {
console.log("give me", this.state.listVisible)
return (
<div className={"dropdown-container" + (this.state.listVisible ? " show" : "")}>
<div className={"dropdown-display" + (this.state.listVisible ? " clicked": "")} onClick={() => this.show()}>
<span>
{this.state.selected.name}
</span>
<i className="fa fa-angle-down"></i>
</div>
<div className="dropdown-list">
<div>
{this.renderListItems()}
</div>
</div>
</div>
)
}
}

Related

How to make a tab active when it is clicked on in React

Good day,
I'm trying to write code to make a tab active when it is clicked on in my React App with Bootstrap. I had previously set only the Home Tab to be active but now I want to change the code. Please how do I go about this? I am new to React.
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, { Component } from 'react';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faCoffee, faCut } from '#fortawesome/free-solid-svg-icons';
class Counter extends Component {
state = {
count: this.props.value,
tabs:["Home","About","Contact","FAQ"]
};
assets={
images:{
image1:"images/la.jpg",
image2:"images/chicago.jpg",
image3:"images/ny.jpg"
},
font:{
font1:"Roboto",
font2:"sans-serif",
font3:"Verdana"
},
styles:{
fontSize:12,
fontWeight:'bold',
fontColor:'whitesmoke'
},
imgstyle:{
borderRadius:"50%",
width:"100px",
height:"100px",
marginTop:"10px"
}
}
formatCount=()=>{
const count=this.state.count;
return count===0?"Zero":count;
};
handleIncrement=()=>{
this.setState({count:this.state.count + 1})
};
styles={
fontSize:15,
fontWeight:"bold"
}
renderTags=()=>{
return(
<nav className="nav nav-tabs">
{this.state.tabs.map(tab=>(
<a href="#" key={tab} className={this.activeNav(tab)}>
{tab}
</a>
))}
</nav>
);
};
formatBadge=()=>{
let classes="badge m-2 badge-";
classes+=this.state.count===0?"warning":"success";
return classes;
};
/*MAKES HOME TAB ACTIVE*/
activeNav=(navlink)=>{
if (navlink==="Home"){
return "nav-item nav-link active"}
else{
return "nav-item nav-link"}
};
render() {
console.log('props',this.props.value)
return (
<div>
<span style={this.styles} className={this.formatBadge()}>
{this.formatCount()}
</span>
<button onClick={this.handleIncrement} className="btn btn-sm btn-secondary m-2"><FontAwesomeIcon icon={faCoffee} className="mr-2"/>Increment</button>
<button className="btn btn-danger btn-sm m-2" onClick={()=>this.props.deleteThis(this.props.id)}><FontAwesomeIcon icon={faCut} className="mr-2"/>Delete</button>
<img style={this.assets.imgstyle} src={this.assets.images.image1} alt=""/>
{this.renderTags()}
</div>
);
}
}
export default Counter;
Any help regarding this would be appreciated. Thank you.
To change the active tab when you click on it, there are three things you need to do:
Maintain a state to track the active tab and move the tabs array out of the state since they are static.
tabs = ["Home", "About", "Contact", "FAQ"];
state = {
count: this.props.value,
activeTabId: 0
};
Change the active tab id when a tab is clicked.
onClick = (id) => {
this.setState({
...this.state,
activeTabId: id
});
};
renderTags = () => {
return (
<nav className="nav nav-tabs">
{this.tabs.map((tab, id) => (
<a
href="#"
key={tab}
onClick={() => this.onClick(id)}
className={this.activeNav(id)}
>
{tab}
</a>
))}
</nav>
);
};
Use the changed state in your tab styling function.
activeNav = (id) => {
if (id === this.state.activeTabId) {
return "nav-item nav-link active";
} else {
return "nav-item nav-link";
}
};
You can find the full code here.
Having said that, there are a couple of things you could do better. You could just ditch the class and use functions for component and use react hooks for handling your states once you do that.

Using useEffect like ComponentDidUpdate

I am trying to have 3 buttons where if one is in an active state, the other 2 will automatically be inactive.
if (isActive === "true") {
setActive2("false")
setActive3("false")
}
if (isActive2 === "true") {
setActive("false")
setActive3("false")
}
if (isActive3 === "true") {
setActive("false")
setActive2("false")
}
I'm aware there's probably a better way of doing this and this is a brute force option, and I'm open to your suggestions.
I have tried putting this block of code in a function and running it whenever the buttons are clicked, but that is giving me the previous state instead of the current state.
So I was suggested to use the useEffect hook.
useEffect(() => {
if (isActive === "true") {
setActive2("false")
setActive3("false")
}
if (isActive2 === "true") {
setActive("false")
setActive3("false")
}
if (isActive3 === "true") {
setActive("false")
setActive2("false")
}
}, [isActive, isActive2, isActive3]);
However this is giving me the same issue, where the previous state is being applied.
I am for sure doing something very wrong with this hook (i have never used it before).
I have a codesandbox with all my code here
Have modified only the onChange handler in an efficient way without touching JSX much and have worked on your set-up only. CodeSandBox Link Checkbox-Selection
Some Major changes that I did are as follows:
Instead of setting seperate state to each button, I have used a single object with 3 keys isActive, isActive2 and isActive3.
const [btnStatus, setBtnStatus] = useState({
isActive: true,
isActive2: true,
isActive3: true
});
Your Handler looks something like this now.
const addPizza = (e) => {
setPizzaSize(e.target.name);
setStartPrice(parseInt(e.target.value));
const currentActive = e.target.id;
if (currentActive === "isActive") {
setBtnStatus({ isActive: true, isActive2: false, isActive3: false });
console.log("1");
}
if (currentActive === "isActive2") {
setBtnStatus({ isActive: false, isActive2: true, isActive3: false });
console.log("2");
}
if (currentActive === "isActive3") {
setBtnStatus({ isActive: false, isActive2: false, isActive3: true });
console.log("3");
}
console.log(btnStatus);
};
In your JSX each button will look like this, with own ids to track the status of button.
<button
name="Extra Large"
className={
btnStatus.isActive3
? "button btn fourth"
: "button btn fourthActive"
}
value="20"
onClick={addPizza}
id="isActive3"
>
Extra large
</button>
And here you go. All working nicely with the same code :)
I have update the code a little bit, you can create seprate constants and use them to reduce the code and also, to keep the active state use a single state only.
https://codesandbox.io/s/gracious-franklin-m8wkx?file=/src/CYO.js:0-4147
import React, { useState, useEffect } from "react";
import ButtonClickable from "./button";
import ButtonClickable2 from "./button2";
import { burgerSize, vegToppings, nonvegToppings } from "./const/size";
import "./index.css";
const CYO = () => {
const [pizzaSize, setPizzaSize] = useState("Choose your Pizza Size");
const [activeSize, setActiveSize] = useState(burgerSize.MEDIUM);
const [toppings, setToppings] = useState([]);
const [startPrice, setStartPrice] = useState(0);
const addPizza = (e) => {
setPizzaSize(e.target.name);
setStartPrice(parseInt(e.target.value));
};
const CheckSize = () => {
if (pizzaSize === "Choose your Pizza Size") {
alert("You must choose a pizza size");
} else if (toppings.length === 0) {
alert("Are you sure you don't want toppings?");
} else {
alert("Sorry, this isn't a real pizza place.");
}
};
const ToppingPlusMinus = (e) => {
const { value } = e.target;
const position = toppings.indexOf(value);
if (position !== -1) {
return removeTopping(value);
}
return addTopping(value);
};
const removeTopping = (value) => {
// We need to filter out the value from the array and return the expected new value
setToppings(toppings.filter((topping) => topping !== value));
//handleToggle();
};
const addTopping = (value) => {
setToppings([...toppings, value]);
// handleToggle();
};
let toppingPrice = toppings.length * 1.5;
let price = startPrice + toppingPrice;
return (
<div className="container CYO">
<h2 className="text-center white">Create your own pizza</h2>
<div className="row">
<div className="col-sm-8">
<div className="">
<img
src="./pizza.png"
className="img-fluid pizza"
alt="Pizza"
></img>
</div>
<h3 className="white">{pizzaSize}</h3>
<p className="white">
Your Toppings: <br />
<div className="col-lg-12">
{toppings
.filter((x) => x.name !== "")
.map((toppings) => (
<img
src={toppings}
alt="topping"
width="100px"
height="100px"
></img>
))}
</div>{" "}
</p>
</div>
<div className="col-sm-4">
<h3 className="white">Pizza size</h3>
{Object.values(burgerSize).map((value) => (
<button
name={value}
className={
activeSize !== value
? "button btn fourth"
: "button btn fourthActive"
}
value="10"
onClick={(event) => {
addPizza(event);
setActiveSize(value);
}}
>
{value}
</button>
))}
<br />
<h3 className="white">Toppings</h3>
<p className="white">Toppings are $1.50 each</p>
<div className="topping-wrapper">
<h4 className="white">Meats</h4>
{nonvegToppings.map(({ name, image }) => (
<ButtonClickable
onClick={(event) => {
ToppingPlusMinus(event);
}}
name={name}
value={image}
/>
))}
<h4 className="white">Veggies</h4>
{vegToppings.map(({ name, image }) => (
<ButtonClickable2
onClick={(event) => {
ToppingPlusMinus(event);
}}
name={name}
value={image}
/>
))}
</div>
</div>
<div className="pricefooter">
<p className="price">Price: ${price}</p>
</div>
<div className="pricefooter2">
<button className="checkout button btn fourth" onClick={CheckSize}>
Checkout
</button>
</div>
</div>
</div>
);
};
export default CYO;

ReactJS rendering issue with edited array

Why does ReactJS remove the last element when the array is different after removing the middle element when using array.splice?
This is my code. I am using React-Redux.
const reducerNotesAndLogin = (state = initialState, action) => {
var tableNotes = "notities";
var tableCategories = "categories";
switch(action.type){
case "CATEGORY_REMOVE":
// Remove the category
var newCategories = state.categories;
console.log("state.categories", state.categories);
console.log("before: ", {newCategories});
var index = 0;
for(var i = 0; i < newCategories.length; i++){
if(newCategories[i].id === action.payload.categoryId){
newCategories.splice(i, 1);
index = i;
i--;
}
}
console.log("after: ", {newCategories});
state = {
...state,
categories: newCategories
}
break;
default:
break;
}
return state;
}
export default reducerNotesAndLogin;
Output below (I deleted the middle element. My web app always removes the last element of the categories (but not from the array).
Step 1: Initial state
Step 2: Remove middle item, expecting the middle item to be removed.
Step 3: Confusion
Why is the array correct, but the view incorrect? I am updating the state.categories correctly right?
This is my render code (as is - without filtering away any other code that mihgt be important)
CategoriesBody:
import React from 'react';
import { connect } from 'react-redux';
import CategoryItem from './CategoryItem';
import Button from './../../Button';
import store from '../../../redux/store-index';
class CategoriesBody extends React.Component {
render(){
return (
<div>
<ul className="list--notes">
{this.props.categories.map((category) => {
if(category.id === undefined){ // No categories
return <li>No categories</li>
} else {
return (
<div>
<CategoryItem category={category} />
<div className="mb-small hidden-sm hidden-md hidden-lg"> </div>
</div>
);
}
})}
</ul>
</div>
);
}
}
function mapStateToProps(state){
return {
categories: state.reducerNotesAndLogin.categories,
categoriesLength: state.reducerNotesAndLogin.categories.length
};
}
export default connect(mapStateToProps)(CategoriesBody);
CategoriesItem.js:
import React from 'react';
import store from './../../../redux/store-index';
import Button from './../../Button';
class CategoryItem extends React.Component {
constructor(props){
super();
this.state = {
edit: false,
categoryName: props.category.categoryName,
categoryColor: props.category.categoryColor
}
this.onClickEdit = this.onClickEdit.bind(this);
this.onChangeCategoryColor = this.onChangeCategoryColor.bind(this);
this.onChangeInputCategoryName = this.onChangeInputCategoryName.bind(this);
this.onClickEditSave = this.onClickEditSave.bind(this);
this.onClickEditCancel = this.onClickEditCancel.bind(this);
}
removeCategory(id, name){
console.log("nsvbsvbfjvbdjhbvv");
store.dispatch({ type: "CATEGORY_REMOVE", payload: {
categoryId: id
}});
// store.dispatch({type: "NOTIFY", payload: {
// type: 'success',
// message: 'Category "' + name + '" removed!'
// }});
}
onClickEdit(){
this.setState({
edit: true
});
}
onChangeCategoryColor(e){
this.setState({
categoryColor: e.target.value
});
}
onChangeInputCategoryName(e){
this.setState({
categoryName: e.target.value
});
}
onClickEditSave(){
this.setState({
edit: false,
categoryName: this.state.categoryName,
categoryColor: this.state.categoryColor
});
store.dispatch({type: "CATEGORY_EDIT", payload: {
categoryId: this.props.category.id,
categoryName: this.state.categoryName,
categoryColor: this.state.categoryColor
}});
store.dispatch({type: "NOTIFY", payload: {
type: "success",
message: "Category saved!"
}});
}
onClickEditCancel(){
this.setState({
edit: false,
categoryName: this.props.category.categoryName,
categoryColor: this.props.category.categoryColor
});
}
render(){
return (
<li key={this.props.category.id} className={this.state.edit === true ? "mt mb" : "flex-justify-between flex-align-center"}>
<div className={this.state.edit === true ? "d-none" : ""}>
<div className="input--color" style={{
backgroundColor: this.state.categoryColor
}}> </div>
{this.state.categoryName}
</div>
{/* Mobile */}
<div className={this.state.edit === true ? "d-none" : "hidden-sm hidden-md hidden-lg"}>
<Button onClick={() => this.onClickEdit()} buttonType="primary">Edit</Button>
<div className="mt-small"> </div>
<Button onClick={() => this.removeCategory(this.props.category.id, this.props.category.categoryName)} type="primary">Remove</Button>
</div>
{/* Tablet and desktop */}
<div className={this.state.edit === true ? "d-none" : "hidden-xs"}>
<div style={{float:'left',}}><Button onClick={() => this.onClickEdit()} buttonType="primary">Edit</Button></div>
<div style={{float:'left',marginLeft:'15px'}}><Button onClick={() => this.removeCategory(this.props.category.id, this.props.category.categoryName)} type="primary">Remove</Button></div>
</div>
{/* EDITING STATE */}
<div className={this.state.edit === true ? "" : "d-none"}>
<div className="row">
<div className="col-xs-12">
<input onChange={this.onChangeCategoryColor} className="input--wide" type="color" value={this.state.categoryColor}
style={{backgroundColor: this.state.categoryColor, height: '30px'}}
/>
<input onChange={this.onChangeInputCategoryName} className="input--wide" type="text" value={this.state.categoryName} />
</div>
</div>
<div className="row mt">
<div className="col-xs-12">
<Button buttonType="primary" onClick={() => this.onClickEditSave()}>Save</Button>
</div>
</div>
<div className="row mt-small">
<div className="col-xs-12">
<Button buttonType="secondary" onClick={() => this.onClickEditCancel()}>Cancel</Button>
</div>
</div>
</div>
</li>
)
}
}
export default CategoryItem;
I think it has something to do with the rendering. Because the arrays are correct when I console.log them. Only the view is different...
Do not modify the state in reducer directly. Create a copy of state value and then modify it.
Change:
var newCategories = state.categories;
To:
var newCategories = [...state.categories];
You should not modify the same array while looping through it.
for (var i = 0; i < newCategories.length; i++) {
if (newCategories[i].id === action.payload.categoryId) {
newCategories.splice(i, 1);
index = i;
i--;
}
}
I got the answer after looking through it with a friend of mine. The solution is pretty simple...
Lesson 101: Make sure that you have a unique "key" property when looping through an array in your UI.
The solution is to add this to my code:
<div key={category.id}>
{this.props.categories.map....
...
</div>

Render a modal when I click a button - React

I have this "trash" button:
<button
type='reset'
className='c-btn--ghost no-border'
onClick={(e) => this.props.handleProjectDelete(e, project.id)}>
<i className='fa fa-trash u-margin-right-tiny'/>
</button>
This is the page with the button.
And when I click it I want a component called CustomModal to render with this props:
<CustomModal
alternateModalClass='c-group-stickies-modal'
onClosePress={this.handleCloseClick}
alternateCloseButtonClass='c-group-stickies-modal__close-button'
text={'are you sure you want to delete it?'}
/>
So a modal like this can appear:
But I don't know how to do that.
This is the component that has the trash button:
https://jsfiddle.net/10u6pfjp/
And this is the CustomModal component: https://jsfiddle.net/cp29ms8g/
As others have mentioned, you should be approaching this with a conditional statement as to whether or not your modal should appear by having a variable in this.state. Change it in your button onClick. Since you now have 2 functions to run, I made a new function called handleProjectDelete in your component to handle both at once.
At the bottom of your render, you'll see that I added the conditional where you should place a modal. I used <Modal/> as a placeholder. Use CSS to force it into a position that's appropriate for a modal.
const MAX_PROJECTS_PER_PAGE = 10
export class ProjectsTable extends Component {
constructor() {
super()
this.state = {
showModal: false
}
}
componentWillReceiveProps(nextProps) {
const { history, organizations, hasFetched } = nextProps
if (!deepEqual(this.props, nextProps) && hasFetched) {
if (!organizations || organizations.isEmpty()) {
history.push('/beta-code')
}
}
}
handleProjectDelete(e, project.id) {
this.setState({showModal: true})
this.props.handleProjectDelete(e, project.id)
}
renderProjectsTable() {
const { projects } = this.props
const projectsWithoutDefault = projects.filter(proj => proj.name !== 'default')
const projectsTable = projectsWithoutDefault.map((project) => {
return ({
name: <NavLink to={`/projects/${project.id}`}> {project.name} </NavLink>,
team: <UsersList users={fromJS(project.users)} showBadge showMax={5} type='list' />,
retro:
(project.lastRetro)
? <NavLink className='c-nav-link'
exact to={`/retrospectives/${project.lastRetro.id}`}>
{moment.utc(project.lastRetro.date)
.format('dddd, DD MMMM YYYY').toString()}
</NavLink> : <div>No retros found</div>,
delete:
<div className='delete-align'>
<button
type='reset'
className='c-btn--ghost no-border'
onClick={(e) => this.handleProjectDelete(e, project.id)}>
<i className='fa fa-trash u-margin-right-tiny'/>
</button>
</div>
})
})
return projectsTable
}
render () {
return (
<div className='o-wrapper u-margin-top'>
<TablePagination
title='Projects'
data={ this.renderProjectsTable()}
headers={['Name', 'Team', 'Last Retrospective', ' ']}
columns='name.team.retro.delete'
nextPageText='>'
prePageText='<'
perPageItemCount={ MAX_PROJECTS_PER_PAGE }
totalCount={ this.renderProjectsTable().length }
arrayOption={ [['size', 'all', ' ']] }
/>
{ this.state.showModal ? <div className='delete-modal'><Modal/><div/> : null }
</div>
)
}
}
const mapStateToProps = ({
projects
}) => ({
hasFetched: projects.get('hasFetched'),
projects: projects.get('projects')
})
ProjectsTable.defaultProps = {
projects: []
}
export default connect(mapStateToProps)(ProjectsTable)
I hope you can do this as below
<button
type='reset'
className='c-btn--ghost no-border'
onClick={(e) => {
this.props.handleProjectDelete(e, project.id);
this.renderModal;
}}>
<i className='fa fa-trash u-margin-right-tiny'/>
</button>

react: strange behaviour on hover

I'm new to React and making a small 'Tweet box' app for practice. There are some strange things which I don't understand...
User can add images to tweets. Images are stored as objects in an array and rendered via looping and running renderThumb() method. On image hover I show a small 'remove icon' in top right of image. When clicked the image is removed.
When I hover an image, ALL images show is hovered (icon is visible on all images). Why?
renderThumb() is executed on hover. Why? (It should only be executed when rendering images).
I use this.state.images.filter( (img) => { return img.id != image.id; } ); to remove image. But it does not work. Why?
// Thanks,
Ole
TweetBox.js
import React, {Component, PropTypes} from 'react';
import './tweetbox.css';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import TextArea from './TextArea';
class TweetBox extends Component {
numPhotoChars = 17;
numStartChars = 140;
author = 'Ole Frank Jensen';
counter = 0;
imageUrl = 'http://i.imgur.com/Crcz7dJ.jpg';
constructor(props) {
super(props);
this.state = {
text: '',
author: this.author,
date: 0,
startValue: this.numStartChars,
images: []
};
this.onTextareaChange = this.onTextareaChange.bind(this);
this.getNumRemainingChars = this.getNumRemainingChars.bind(this);
this.disableTextarea = this.disableTextarea.bind(this);
this.addImage = this.addImage.bind(this);
this.removeImage = this.removeImage.bind(this);
this.submitTweet = this.submitTweet.bind(this);
this.onMouseOver = this.onMouseOver.bind(this);
this.onMouseOut = this.onMouseOut.bind(this);
}
onTextareaChange(e) {
this.setState({text: e.target.value});
}
getNumRemainingChars() {
return this.state.startValue - this.state.text.length;
}
disableTextarea() {
return this.state.text.length > 0 || this.state.images.length;
}
addImage() {
if (this.getNumRemainingChars() >= this.numPhotoChars) {
const startValue = this.state.startValue - this.numPhotoChars;
const image = Object.assign({}, {
id: this.counter += 1,
url: this.imageUrl
});
this.setState({startValue: startValue});
this.setState({images: [...this.state.images, image]});
}
}
removeImage(image) {
let arr = this.state.images.filter( function(img) { return img.id != image.id; } );
console.log(image, arr);
this.setState({
images: this.state.images.filter( function(img) { return img.id != image.id; } ),
startValue: this.state.startValue + this.numPhotoChars,
hover: false
});
}
submitTweet(e) {
e.preventDefault();
// compose
const tweet = {
text: this.state.text,
author: this.state.author,
date: new Date().getTime(),
images: this.state.images
};
// store
this.props.storeTweet(tweet);
// reset
this.setState({
text: '',
images: [],
startValue: this.numStartChars
});
}
onMouseOver() { console.log('over'); this.setState({hover: true}); }
onMouseOut() { console.log('out'); this.setState({hover: false}); }
renderThumb(image, index) {
console.log(index);
let k = 'image-' + index;
return (
<div key={k} className="col-xs-3">
<div className="thumbnail-wrapper">
<img src={image.url}
alt="My something"
className="img-thumbnail"
onMouseOver={ this.onMouseOver }
onMouseOut={ this.onMouseOut }/>
<div className={"img-thumbnail-close-btn " + (this.state.hover ? 'show' : 'hidden')}
onMouseOver={ this.onMouseOver }
onMouseOut={ this.onMouseOut }
onClick={ () => { this.removeImage({image}) } }>
<span className="fa-stack fa-1x">
<i className="fa fa-circle fa-stack-2x white-background"></i>
<i className="fa fa-circle-thin fa-stack-2x black-border"></i>
<i className="fa fa-times fa-stack-1x"></i>
</span>
</div>
</div>
</div>
);
}
render() {
return (
<div className="tweet-box">
<div className="row">
<div className="col-xs-6 col-xs-offset-3">
<div className="well tweet-box clearfix">
<h1>Tweet Box</h1>
<TextArea value={ this.state.text }
maxLength={this.state.startValue}
onChange={this.onTextareaChange}/>
<span className="pull-right">
<em>{this.getNumRemainingChars()} characters left...</em>
</span>
<br/>
<div className="row">
<ReactCSSTransitionGroup transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={500}>
{
this.state.images.map((image, index) => {
return this.renderThumb(image, index);
})
}
</ReactCSSTransitionGroup>
</div>
<br/>
<div className="row">
<div className="col-xs-6">
<button className="btn btn-default add-photo pull-left"
onClick={this.addImage}>
<i className="fa fa-camera"></i> Add photo
</button>
</div>
<div className="col-xs-6">
<button onClick={this.submitTweet} className="btn btn-primary pull-right"
disabled={!this.disableTextarea()}>
<i className="fa fa-pencil-square-o"></i> Tweet!
</button>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
TweetBox.propTypes = {
storeTweet: PropTypes.func.isRequired
};
export default TweetBox;
Your state is designed to be general, id suggest you to add id on each image. and add a handler that accepts that id. that way you can change the hover of specific image only.
this.setState({hover: true})
you can see below that you are adding the same handler to all the images,
so one image hovered will result to them all being hovered.
<img src={image.url}
alt="My something"
className="img-thumbnail"
onMouseOver={ this.onMouseOver }
onMouseOut={ this.onMouseOut }/>

Categories