I want to have 3 buttons and 3 related components . So that when button click show its related component . Here is my code :
Main Component :
class Main extends Component { constructor(props) {
super(props);
this.state = {
show: false,
}}
onClick(e) {
e.preventDefault()
console.log(e.target.id)
this.setState({ show: !this.state.show }); }
renderTabs() {
var child = this.props.child;
var items = [];
__.forEach(child, (item, index) => {
items.push(
<div>
<Button id={index} onClick={(e) => this.onClick(e)}>{item.data}</Button>
{this.state.show ? (
<CropComponent title={item.data} opts={item.opts} data={item.child} />
) : null}
</div>
);
});
return items;
}
render() {
var opts = this.props.opts;
return (
<div>
{this.renderTabs()}
</div>
)}
}
export default Main;
And here is my CropComponent :
class CropComponent extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div>hello {this.props.data}</div>
);
}
}
export default CropComponent;
Here are my buttons how can i show its related component when click on a button and hide it on re-click the same button ?
Maintain a show state with initial value as -1. Supply event and index to onClick. In onClick do setState of show as index.
Check if show === index and render the corresponding component.
Like this
this.state = {
show: -1
}
onClick(e,index) {
e.preventDefault()
this.setState({ show: show===index? -1 : index});
}
__.forEach(child, (item, index) => {
items.push(
<div>
<Button id={index} onClick={(e) => this.onClick(e,index)}>{item.data}</Button>
{this.state.show === index ? (
<CropComponent title={item.data} opts={item.opts} data={item.child} />
) : null}
</div>
);
});
Edit:
updated the answer based on helpful comment by #Tony Nguyen
Related
i have this breadcrump component that map over props and renders a list of chip components like this:
class BreadCrumb extends React.Component {
render () {
const {
steps,
activeIndex
} = this.props;
const chips = steps
.map((step,index) => {
return <Chip
key={index}
title={step.category}
onClick = {()=> this.props.selectChip(index)} // this should be passed only if
// active == true
active={activeIndex >= index} />
})
return (
<div className="chip-container">
{chips}
</div>
)
}
}
i need to click on chips only if his active prop is true,
this is the chip component
class Chip extends React.Component {
render(){
const {
active,
title
} = this.props;
const activeClassName = active ? 'chip active' : 'chip';
return (
<div
className = {activeClassName}
onClick = {() => this.props.onClick()} >
<span>{title}</span>
</div>
)
}
}
how can i make chip clickable only if the active prop is true?
For further information selectChip() function sets the state of a component App, parent of Breadcrump component, so it is binded to App component.
You could e.g. make that onClick function as a class method and use a simple condition inside:
class Chip extends React.Component {
handleClick = () => {
if (this.props.active) {
this.props.onClick(); // call only if active props is true
}
}
render() {
const { active, title } = this.props;
const activeClassName = active ? 'chip active' : 'chip';
return (
<div
className = {activeClassName}
onClick = {this.handleClick}
>
<span>{title}</span>
</div>
)
}
}
Either execute the handler or an empty function
onClick = {isActive ? this.props.onClick : () =>{} } >
You can do it like this:-
// If chip component expects a function all the time
<Chip
key={index}
title={step.category}
onClick = {step.active ? ()=> this.props.selectChip(index) : () => {}}
active={activeIndex >= index} />
// If onClick is an optional prop to chip component
<Chip
key={index}
title={step.category}
onClick = {step.active ? ()=> this.props.selectChip(index) : undefined}
active={activeIndex >= index} />
// of onClick handler is optional, possibly an alternative solution
type ChipProps = {
title: string;
active: boolean;
onClick?: ()=>void;
}
<Chip
key={index}
title={step.category}
active={activeIndex >= index}
{...(step.active ? {onClick:()=> this.props.selectChip(index)} : {})}
/>
I'm using the react-image-lighbox npm package https://www.npmjs.com/package/react-image-lightbox and i am trying to get it to work with my custom code. I have a gallery and i am trying to get it to display an image in a lightbox when you click on a button in the array. At the moment when you click on any of the buttons it opens up all of them at the same time in an array. I need to have it filtered so that it only opens the image that you clicked on not all of them.
At the moment i am playing around with filter and if statements to try and find a solution.
Example of some of the state passed down through props.
portfolioContent: [
{
id: uuidv1(),
imgURL: image01,
text: 'Copy 1',
section: 1,
work:
'https://images2.minutemediacdn.com/image/upload/c_crop,h_1193,w_2121,x_0,y_64/f_auto,q_auto,w_1100/v1565279671/shape/mentalfloss/578211-gettyimages-542930526.jpg'
},
{
id: uuidv1(),
imgURL: image02,
text: 'Copy 2',
section: 1,
work:
'https://images2.minutemediacdn.com/image/upload/c_crop,h_1193,w_2121,x_0,y_175/f_auto,q_auto,w_1100/v1554921998/shape/mentalfloss/549585-istock-909106260.jpg'
}
]
<Main portfolio={this.state.portfolioContent} />
<PortfolioWork work={this.props.portfolio} section="1" />
import React, { Component, Fragment } from 'react';
import Lightbox from 'react-image-lightbox';
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
const images = [
'//placekitten.com/1500/500',
'//placekitten.com/4000/3000',
'//placekitten.com/800/1200',
'//placekitten.com/1500/1500',
];
export default class LightboxExample extends Component {
constructor(props) {
super(props);
this.state = {
photoIndex: 0,
isOpen: false,
};
}
render() {
const { photoIndex, isOpen } = this.state;
return (
<Fragment>
{this.props.work.map(portfolio => {
if (portfolio.section === Number(this.props.section)) {
return (
<div className="portfolio-content" key={portfolio.id}>
<img src={portfolio.imgURL} alt={portfolio.text} />
<p>{portfolio.text}</p>
<a href={portfolio.work}>See work</a>
<button type="button" onClick={() => this.setState({ isOpen: true })}>
Open Lightbox
</button>
{isOpen && (
<Lightbox
mainSrc={portfolio.imgURL}
nextSrc={images[(photoIndex + 1) % images.length]}
prevSrc={images[(photoIndex + images.length - 1) % images.length]}
onCloseRequest={() => this.setState({ isOpen: false })}
onMovePrevRequest={() =>
this.setState({
photoIndex: (photoIndex + images.length - 1) % images.length,
})
}
onMoveNextRequest={() =>
this.setState({
photoIndex: (photoIndex + 1) % images.length,
})
}
/>
)}
</div>
);
}
})}
</Fragment>
);
}
}
Clicking on a button opens up that image in a lightbox. At the moment if you click on any button it opens up all of the images at the same time in a lighbox.
I figured it out. So i created a function in the main App.js file which took in an object. And then i passed down that function to the component through props and attached it to a click event. So that when the user clicks on the button it is assigned to its corresponding object. I then set that object to state and made the selected image object the main source for the lightbox image which gets displayed.
import React, { Component, Fragment } from 'react';
import Lightbox from 'react-image-lightbox';
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
export default class LightboxExample extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
}
render() {
const { isOpen } = this.state;
return (
<Fragment>
{this.props.work.map(portfolio => {
if (portfolio.section === Number(this.props.section)) {
return (
<div key={portfolio.id}>
<div className="portfolio-content">
<img src={portfolio.imgURL} alt={portfolio.text} />
<p>{portfolio.text}</p>
<button
type="button"
onClick={() => {
this.setState({ isOpen: true });
this.props.onImageSelect(portfolio);
}}
>
See work
</button>
</div>
<div>
{isOpen && (
<Lightbox
mainSrc={this.props.selectedImage.imgURL}
onCloseRequest={() => this.setState({ isOpen: false })}
/>
)}
</div>
</div>
);
}
})}
</Fragment>
);
I am trying to create a component where I have a bunch of boxes from an array, that can be turned 'on' and 'off' when each one is individually clicked.
Currently, only a single item from the array can be switched 'on' (shown by the item turning green), however, I would like to be able to turn each item on/off individually.
Interacting with one element should not affect any of the others.
How do I achieve this?
My click event:
handleOnClick = (val, i) => {
this.setState({active: i}, () => console.log(this.state.active, 'active'))
}
Rendering the boxes:
renderBoxes = () => {
const options = this.state.needsOptions.map((val, i) => {
return (
<button
key={i}
style={{...style.box, background: i === this.state.active ? 'green' : ''}}
onClick={() => this.handleOnClick(val, i)}
>
{val}
</button>
)
})
return options
}
Here's a Codepen
What I would do is to create a Box component with its own active state, and pass this to the map in renderBoxes. The benefit of doing it this way is that each Box component will have its own state independent of the parent. That way you can have more than one component as active.
so...
class Box extends React.Component {
constructor(props){
super(props)
this.state={
active: false
}
}
clickHandler = () => {
this.setState({active: !this.state.active})
}
render(){
const { key, children }= this.props
return (
<button
key={key}
style={{...style.box, background: this.state.active ? 'green' : ''}}
onClick={() => this.clickHandler()}
>
{children}
</button>
)
}
}
then have renderBoxes be...
renderBoxes = () => {
const options = this.state.needsOptions.map((val, i) => {
return (
<Box
key={i}
>
{val}
</Box>
)
})
return options
}
here is the codepen I forked off yours.
I'm new to ReactJS and I would like to communicate between my components.
When I click an image in my "ChildA" I want to update the correct item image in my "ChildB" (type attribute in ChildA can only be "itemone", "itemtwo", "itemthree"
Here is what it looks like
Parent.js
export default class Parent extends Component {
render() {
return (
<div className="mainapp" id="app">
<ChildA/>
<ChildB/>
</div>
);
}
}
if (document.getElementById('page')) {
ReactDOM.render(<Builder />, document.getElementById('page'));
}
ChildA.js
render() {
return _.map(this.state.eq, ecu => {
return (
<img src="../images/misc/ec.png" type={ecu.type_eq} onClick={() => this.changeImage(ecu.img)}/>
);
});
}
ChildB.js
export default class CharacterForm extends Component {
constructor(props) {
super(props);
this.state = {
items: [
{ name: "itemone" image: "defaultone.png"},
{ name: "itemtwo" image: "defaulttwo.png"},
{ name: "itemthree" image: "defaultthree.png"},
]
};
}
render() {
return (
<div className="items-column">
{this.state.items.map(item => (<FrameCharacter key={item.name} item={item} />))}
</div>
);
}
}
I can retrieve the image on my onClick handler in my ChildA but I don't know how to give it to my ChildB. Any hints are welcomed, thanks you!
What you need is for Parent to pass an event handler down to ChildA which ChildA will call when one of the images is clicked. The event handler will call setState in Parent to update its state with the given value, and then Parent will pass the value down to ChildB in its render method.
You can see this working in the below example. Since I don't have any actual images to work with—and to keep it simple—I've used <button>s instead, but the principle is the same.
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
clickedItem: 'none',
};
}
render() {
return (
<div>
<ChildA onClick={this.handleChildClick}/>
<ChildB clickedItem={this.state.clickedItem}/>
</div>
);
}
handleChildClick = clickedItem => {
this.setState({ clickedItem });
}
}
const items = ['item1', 'item2', 'item3'];
const ChildA = ({ onClick }) => (
<div>
{items.map(name => (
<button key={name} type="button" onClick={() => onClick(name)}>
{name}
</button>
))}
</div>
);
const ChildB = ({clickedItem}) => (
<p>Clicked item: {clickedItem}</p>
);
ReactDOM.render(<Parent/>, document.querySelector('div'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.development.js"></script>
<div></div>
I'm working on building my portfolio using React.js. In one section, I have four components laid out in a grid. What I want to do achieve is when one component is clicked, a css class is added to the siblings of this component so that their opacity is reduced and only the clicked component remains. In jQuery, it would be something like $('.component').on('click', function(){ $(this).siblings.addClass('fadeAway')}). How can I achieve this effect? Here is my code, thanks in advance for any and all help!
class Parent extends Component{
constructor(){
super();
this.state = {fadeAway: false}
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
//Add class to siblings
}
render(){
const array = ["Hello", "Hi", "How's it going", "Good Times"]
return(
array.map(function(obj, index){
<Child text={obj} key={index} onClick={() => this.handleClick} />
})
)
}
}
A working example for this problem could look something like this, with a marginally more complex initialization array:
class Parent extends Component{
constructor(){
super();
this.state = {
elements: [
{
id: "hello",
text: "Hello",
reduced: false,
},
{
id: "hi",
text: "Hi",
reduced: false,
}
{
id: "howsItGoing"
text: "How's it going",
reduced: false,
}
{
id: "goodTimes",
text: "Good Times",
reduced: false,
}
],
}
this.handleClick = this.handleClick.bind(this)
}
handleClick(e){
// copy elements from state
const elements = JSON.parse(JSON.stringify(elements));
const newElements = elements.map(element => {
if (element.id === e.target.id) {
element.reduced = false;
} else {
element.reduced = true;
}
});
this.setState({
elements: newElements,
});
}
render(){
return(
this.state.elements.map(function(obj, index){
<Child
id={obj.id}
text={obj.text}
reduced={obj.reduced}
key={index}
onClick={() => this.handleClick} />
});
);
}
}
Then you would just add a ternary, like so, to the Child component:
<Child
id={this.props.id}
className={this.props.reduced ? "reduced" : ""} />
This adds a bit more boilerplate than other examples, but it's extremely brittle to tie business logic to the text inside a component, and a stronger solution requires a stronger piece of identification, like an ID or class on the rendered DOM element. This solution also, if you so wish, easily allows you to expand your logic so that more than one element can remain at maximum opacity at once.
I would simply store in state index of selected item, and then pass fadeAway prop into Child component defined as
fadeAway={this.state.selectedIndex !== index}
After that you only need to set a fade-away class in Child based on this.prop.fadeAway and define necessary CSS rules.
Here is how it could look in your case:
class Parent extends React.Component{
constructor () {
super();
this.state = {selectedIndex: null}
}
handleClick (selectedIndex) {
this.setState({ selectedIndex })
}
render () {
const array = ["Hello", "Hi", "How's it going", "Good Times"]
return (
<div>
{array.map((obj, index) => {
const faded = this.state.selectedIndex && this.state.selectedIndex !== index
return <Child
text={obj}
fadeAway={faded}
key={index}
onClick={() => this.handleClick(index)} />
})}
</div>
)
}
}
class Child extends React.Component {
render () {
return (
<h2
onClick={this.props.onClick}
className={this.props.fadeAway ? 'fade-away' : ''}>
{this.props.text}
</h2>
)
}
}
ReactDOM.render(
<Parent />,
document.body
);
.fade-away {
opacity: 0.3;
}
<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>
You can achieve that using using a toggle variable :
handleClick(){
this.setState({fadeAway} => ({
fadeAway: ! fadeAway
)};
}
...
<Child
text={obj}
key={index}
onClick={() => this.handleClick}
className={this.state.fadeAway? 'class1' : 'class2'}/>
I perfer use state like currentWord to save the word was clicked in Parent component, presudo code is like below:
class Parent extends Component {
constructor(){
super();
this.state = {
fadeAway: false,
currentWord: ''
};
this.handleClick = this.handleClick.bind(this)
}
handleClick(currentWord){
this.setState({
currentWord: currentWord,
});
}
render(){
const array = ["Hello", "Hi", "How's it going", "Good Times"]
const currentWord = this.state.currentWord;
return(
array.map(function(obj, index){
<Child currentWord={currentWord} text={obj} key={index} onClick={() => this.handleClick} />
})
)
}
}
And in Child component
class Child extends Component {
// some other code
handleClick(e) {
this.props.handleClick(e.target.value);
}
render() {
const isSelected = this.props.text === this.props.currentWord;
// use isSelected to toggle className
<div
onClick={this.handleClick.bind(this)}
>{this.props.text}
</div>
}
}