I'm trying to build a photo gallery in React. So far I have an App component and a Photo component. The details for my images lives in the App components state, and I want to pass the images down to the Photo component. So far, so good.
However, when I try to assign the <img /> tag the appropriate source using the image props, it doesn't work. I'm doing this by <img src={ this.props.images.src } />. When I log it to the console, the value is undefined.
What's going on?
Code for the App component:
import React, { Component } from 'react';
import Photo from './components/Photo';
import images from './data/images';
import './App.css';
import './css/Photo.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
images: images,
visible: false,
modalClass: 'photo-modal-invisible'
};
}
handleClick(index) {
const isVisible = this.state.visible;
if(isVisible === false) {
this.setState({ visible: true, visibleClass: 'photo-modal-visible', activeImage: images[index] });
} else {
this.setState({ visible: false, visibleClass: 'photo-modal-invisible' });
}
}
render() {
return (
<div className="App">
<React.Fragment>
<div className="photo-container">
{
this.state.images.map((image, index) =>
<Photo
images={ this.state.images }
visible={ this.state.visible }
modalClass={ this.state.modalClass }
/>
)
}
</div>
</React.Fragment>
</div>
);
}
}
export default App;
Code for the Photo component:
import React, { Component } from 'react';
import './../css/Photo.css';
class Photo extends Component {
constructor(props) {
super(props);
}
render() {
return(
<img src={ this.props.images.src } />
);
}
}
export default Photo;
Image data:
export default [{
title: 'Mountain Road',
photographer: 'Emma Ayers',
alt: 'Mountain Road',
src: '/assets/images/image1.png'
}, {
title: 'Fall Forest',
photographer: 'Emma Ayers',
alt: 'Fall Forest',
src: '/assets/images/image2.png'
}, {
title: 'Flower Bridge',
photographer: 'Emma Ayers',
alt: 'Flower Bridge',
src: '/assets/images/image3.png'
}, {
title: 'Dry River',
photographer: 'Emma Ayers',
alt: 'Dry River',
src: '/assets/images/image4.png'
}, {
title: 'Moony Mountains',
photographer: 'Emma Ayers',
alt: 'Moony Mountains',
src: '/assets/images/image5.png'
}, {
title: 'Snowy Mountains',
photographer: 'Emma Ayers',
alt: 'Snowy Mountains',
src: '/assets/images/image6.png'
}
];
The problem lies within your map method, you are passing in the whole array (this.state.images) that you are attempting to map over. You can think of map as a functional for loop, so for each image you loop over, you are returning a <Photo /> and each instance of that loop is one of your objects that you defined within image data file.
this.state.images.map((image, index) => (
<Photo
image={image} // the fix
visible={this.state.visible}
modalClass={this.state.modalClass}
/>
)
and then in your Photo component
<img src={this.props.image.src} />
You should just pass one image to Photo component
<React.Fragment>
<div className="photo-container">
{
this.state.images.map((image, index) =>
<Photo
image={ image }
visible={ this.state.visible }
modalClass={ this.state.modalClass }
/>
)
}
</div>
</React.Fragment>
You don't need to make photo as stateful component. stateless functional component is enough for displaying just view.
const Photo (props) => (
<img src={ props.image.src } />
);
}
}
export default Photo;
app component:
import React, { Component } from 'react';
import Photo from './components/Photo';
import images from './data/images';
import './App.css';
import './css/Photo.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
images: images,
visible: false,
modalClass: 'photo-modal-invisible'
};
}
handleClick = (index) => {
const isVisible = this.state.visible;
if(isVisible === false) {
this.setState({ visible: true, visibleClass: 'photo-modal-visible', activeImage: images[index] });
} else {
this.setState({ visible: false, visibleClass: 'photo-modal-invisible' });
}
}
render() {
return (
<div className="App">
<React.Fragment>
<div className="photo-container">
{
this.state.images.map((image, index) =>
<Photo
images={image}
visible={this.state.visible}
modalClass={this.state.modalClass}
onClick={(index) => this.handleClick(index)}
/>
)
}
</div>
</React.Fragment>
</div>
);
}
}
export default App;
photo component:
import React, { Component } from 'react';
import './../css/Photo.css';
class Photo extends Component {
constructor(props) {
super(props);
}
render() {
return(
<img src={ this.props.images.src alt={this.props.images.alt}} />
);
}
}
export default Photo;
Here problem was image map function.. While passing the map function argument you are passing the direct state of image array here. So map works as in loop with image array object.
Here for active image, please share the use case so that I can give you better way to handle it.
Related
Hello peepz of the web,
I've ran into mysterious corridor, which's too dark for me to see what the hell I'm going.. would love someone's flashlight to shine the way.
I have created a simple, poor to do list program.
It's combined from Task.js, TaskList.js and NewTaskForm.js.
From the NewTaskForm.js I'm retrieving input, passing it to the parent, TaskList.js.
On TaskList.js I'm adding a key to the task object:
handleSubmit(task2add){
let keyid = v4();
console.log(keyid);
let task2addWithID = { ...task2add, id: {keyid}, key: {keyid}};
this.setState(st => ({
todoArr: [...st.todoArr, task2addWithID],
}));
}
Now, in TaskList.js, in my render function, I'm creating Tasks:
render() {
let tasklist = this.state.todoArr.map(task => (
<div>
<Task
taskTitle={task.title}
taskText={task.text}
key={task.key}
id={task.id}
handleRemove={this.handleRemove}
handleEdit={this.handleEdit}
/>
</div>
));
return (
<div>
<h1>TaskList</h1>
<div className='TaskList'>
<div className='TaskList-title'>
{tasklist}
</div>
<NewTaskForm key={1} handleSubmit={this.handleSubmit}/>
</div>
</div>
)
}
now, what is so confusing for me is why when I'm doing in my Tasks.js class:
console.log(this.props.id);
it prints me an object?
I would expect it to.. print me a value? where along the way did it wrap it with an object?
Full (shitty) code below.
Plus #1, if anyone knows to tell me why still I get the warning the key, even though, at least for my poor experience, I have given it a key?
Plus #2, why even when I send the handleRemove function in TaskList.js the proper id, it doesn't erase the bloody task? :-(
Regards!
Task.js
import React, { Component } from 'react'
import './Task.css';
export default class Task extends Component {
constructor(props){
super(props);
this.handleRemove = this.handleRemove.bind(this);
}
handleRemove(evt){
evt.preventDefault();
console.log("MY ID MANNN");
console.log(this.props.id);
this.props.handleRemove(this.props.id.keyid);
console.log("CALLED");
}
render() {
return (
<div className='Task'>
<div className='Task-title'>
{this.props.taskTitle}
</div>
<div className='Task-text'>
{this.props.taskText}
</div>
<div>
<button className='Task-buttons'>Edit</button>
<button className='Task-buttons' onClick={this.handleRemove}>Delete</button>
</div>
</div>
)
}
}
NewTaskForm.js:
import React, { Component } from 'react';
import {v4} from 'uuid';
export default class NewTaskForm extends Component {
constructor(props){
super(props);
this.state = {
title: "", text: "", editing: false
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
// this.handleRemove = this.handleRemove.bind(this);
}
handleSubmit(evt){
evt.preventDefault();
// let stateWithID = { ...this.state, id: useId()};
this.props.handleSubmit(this.state);
this.setState({
title: "",
text: ""
})
}
handleChange(evt){
evt.preventDefault();
this.setState({
[evt.target.name]: evt.target.value
});
}
render() {
return (
<div>
<h2>Insert new Task:</h2>
<form onSubmit={this.handleSubmit}>
<label htmlFor="title">Title</label>
<input
name='title'
id='title'
type='text'
onChange={this.handleChange}
value={this.state.title}
/>
<div>
<label htmlFor="text">text</label>
<input
name='text'
id='text'
type='text'
onChange={this.handleChange}
value={this.state.text}
/>
</div>
<button>Submit</button>
</form>
</div>
)
}
}
TaskList.js
import React, { Component } from 'react'
import NewTaskForm from './NewTaskForm';
import Task from './Task';
import './TaskList.css';
import {v4} from 'uuid';
export default class TaskList extends Component {
constructor(props){
super(props);
this.state = {
todoArr: [
// {title: "test", text: "this shit", key: "", id: ""},
// {title: "test2", text: "this shi2", key: "", id: ""},
// {title: "test3", text: "this shi3", key: "", id: ""}
],
isEditing: false,
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleRemove = this.handleRemove.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
handleSubmit(task2add){
let keyid = v4();
console.log(keyid);
let task2addWithID = { ...task2add, id: {keyid}, key: {keyid}};
this.setState(st => ({
todoArr: [...st.todoArr, task2addWithID],
}));
}
handleRemove(keyid){
console.log("IN HANDLE REMOVE");
console.log(keyid);
this.setState(st => ({
todoArr: st.todoArr.filter(n => n.keyid !== keyid )
}));
}
handleEdit(id){
}
render() {
let tasklist = this.state.todoArr.map(task => (
<div>
<Task
taskTitle={task.title}
taskText={task.text}
key={task.key}
id={task.id}
handleRemove={this.handleRemove}
handleEdit={this.handleEdit}
/>
</div>
));
return (
<div>
<h1>TaskList</h1>
<div className='TaskList'>
<div className='TaskList-title'>
{tasklist}
</div>
<NewTaskForm key={1} handleSubmit={this.handleSubmit}/>
</div>
</div>
)
}
}
Because you have created an object here:
{ ...task2add, id: {keyid}, key: {keyid}};
{keyid}
is the same as
{keyid: keyid}
You wanted to do this:
{ ...task2add, id: keyid, key: keyid};
I'm assuming its because you're setting the state like this:
let task2addWithID = { ...task2add, id: {keyid}, key: {keyid}};
The id attribute is assigned an object. If you did:
let task2addWithID = { ...task2add, id: keyid, key: {keyid}};
console logging id should print out a string
Hi i want to create a dropDown in react with each item having an icon. As i tried react-select but its not showing the icon ,and also the selected value .When i remove value prop from react-select component than the label is showing. I want to create the dropdown like the this.
//USerInfo.js
import React from "react";
import { connect } from "react-redux";
import FontAwesome from "react-fontawesome";
import Select from "react-select";
import { setPresence } from "../../ducks/user";
import "./UserInfo.css";
class UserInfo extends React.Component {
// constructor(props) {
// super(props);
// this.state = {
// currentPresence: "available",
// };
// }
presenceOpts = [
{ value: "available", label: "Available" },
{ value: "dnd", label: "Busy" },
{ value: "away", label: "Away" },
];
setPresenceFun(presence) {
this.props.setPresence(presence);
}
renderPresenceOption(option) {
return (
<div className="presenceOption">
<FontAwesome name="circle" className={"presenceIcon " + option.value} />
{option.label}
</div>
);
}
renderPresenceValue(presence) {
return (
<div className="currentPresence">
<FontAwesome
name="circle"
className={"presenceIcon " + presence.value}
/>
</div>
);
}
render() {
return (
<div className="UserInfo">
{this.props.client.authenticated && (
<div className="authenticated">
<div className="user">
<div className="presenceControl">
<Select
name="presence"
value={this.props.user.presence.value}
options={this.presenceOpts}
onChange={this.setPresenceFun.bind(this)}
clearable={false}
optionRenderer={this.renderPresenceOption}
valueRenderer={this.renderPresenceValue}
/>
</div>
<div className="username">
<p>{this.props.client.jid.local}</p>
</div>
</div>
</div>
)}
</div>
);
}
}
const mapStateToProps = (state, props) => ({
client: state.client,
user: state.user,
});
const mapDispatchToProps = (dispatch, props) => {
return {
setPresence: (presence) => dispatch(setPresence(presence)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UserInfo);
You can customize the option for dropdown
This may assist you in resolving the custom styling issue with react select.
https://codesandbox.io/s/react-select-add-custom-option-forked-u1iee?file=/src/index.js
I'm studying a React app made up by one main component: App.js (the main one) and three other external components: Dog.js, DogItem.js, AddDog.js The App contain a set of items (Dogs): Dog.js, made up of single dog elements, DogItem.js, and a form: AddDog.js to add a new item: dog.
In the AddDog.js file, the only line I don't realize is: this.props.addDog(this.state.newDog); I have highlighted it below.
I'd like to underline that addDog in this.props.addDog(this.state.newDog); is different from the name of the component AddDog.
Here's AddDog.js
import React, { Component } from 'react';
class AddDog extends Component {
constructor() {
super();
this.state = {
newDog:{}
}
}
static defaultProps = {
categories: ['Web Design', 'Web Development', 'Mobile Development']
}
handleSubmit(e) {
if(this.refs.name.value === '') {
alert('Title is required');
} else if (this.refs.image.value === '') {
alert('Image link is required');
} else if (this.refs.breed.value === '') {
alert('Breed is required');
} else {
this.setState({newDog:{
name: this.refs.name.value,
breed: this.refs.breed.value,
image: this.refs.image.value
}}, function() {
this.props.addDog(this.state.newDog); // <<<<<<<<<<<<<<<<<
});
}
e.preventDefault();
}
render() {
return (
<div>
<h3 id="addDog">Add Dog</h3>
<form onSubmit={this.handleSubmit.bind(this)}>
<div>
<label>Name</label><br />
<input id="dogName" type="text" ref="name" />
</div>
<div>
<label>Image</label><br />
<input id="imageURL" type="text" ref="image" />
</div>
<div>
<label>Breed</label><br />
<input id="dogBreed" type="text" ref="breed" />
</div>
<br />
<input id="submitButton" type="submit" value="Submit" />
<br />
</form>
</div>
);
}
}
export default AddDog;
Here's the App.js
import React, { Component } from 'react';
import Dogs from './components/Dogs';
import DogItem from './components/DogItem';
import AddDog from './components/AddDog';
import './App.css';
class App extends Component {
constructor() {
super();
this.state = {
dogs: []
};
}
getDogs() {
var defaultDogs = {dogs: [
{
name: 'Princess',
breed: 'Corgi',
image: 'https://s-media-cache-ak0.pinimg.com/originals/51/ae/30/51ae30b78696b33a64661fa3ac205b3b.jpg'
},
{
name: 'Riley',
breed: 'Husky',
image: 'http://portland.ohsohandy.com/images/uploads/93796/m/nice-and-sweet-siberian-husky-puppies-for-free-adoption.jpg'
},
]};
this.setState(defaultDogs);
}
componentWillMount() { // this soon display the two dogs before the render
this.getDogs();
}
handleAddDog(dog) {
let dogs = this.state.dogs;
dogs.push(dog);
this.setState({dogs:dogs});
}
handleDeleteDog(name) {
let dogs = this.state.dogs;
let index = dogs.findIndex(x => x.name === name); // function (x) {return x.name === name} is like x => x.name === name
dogs.splice(index, 1);
this.setState({dogs:dogs});
}
render() {
return (
<div className="App">
<Dogs dogs={this.state.dogs} onDelete={this.handleDeleteDog.bind(this)} />
<AddDog addDog={this.handleAddDog.bind(this)} />
<hr />
</div>
);
}
}
export default App;
Here's Dog.js
import React, { Component } from 'react';
import DogItem from './DogItem';
class Dogs extends Component {
deleteDog(name) {
this.props.onDelete(name);
}
render() {
let dogItem;
if (this.props.dogs) {
dogItem = this.props.dogs.map(dog => {
return (
<DogItem onDelete={this.deleteDog.bind(this)} key={dog.name} dog={dog} />
);
});
}
return (
<div className="Dogs">
<h1>Good Dogs</h1>
{dogItem}
</div>
);
}
}
export default Dogs;
Here's DogItem.js
import React, { Component } from 'react';
class DogItem extends Component {
deleteDog(name) {
this.props.onDelete(name);
}
render() {
return (
<ul className="Dog">
<img src={this.props.dog.image} href={this.props.dog.image} role="presentation" width="100" height="100"></img>
<br></br>
<strong>{this.props.dog.name}</strong>: {this.props.dog.breed} <a href="#" onClick={this.deleteDog.bind(this, this.props.dog.name)}>X</a>
<br></br>
</ul>
);
}
}
export default DogItem;
It's a callback function from the parent component. (In this case App.js)
It's used to add the new dog into the dogs array in the App's state.
So when you the function this.props.addDog(this.state.newDog) is called, it's calling the function that has been passed in as a prop by the parent component
(<AddDog addDog={this.handleAddDog.bind(this)} /> in App.js)
Which means when you call this.props.addDog(this.state.newDog),
this.handleAddDog() gets called in the App.js component with the new Dog Object as the argument (this.handleAddDog(this.state.newDog) with "this.state" refering to the state of the AddDog Component)
I hope that was detailed and clear enough ;)
I want to set that when I click onClick in the component Albums.js, I get the contents of the component photos.js. Specifically, choosing one album will trigger a photo array from this album using the Photos.js component.
Albums.js
import React from 'react';
import PropTypes from 'prop-types';
import './forAlbum.css'
class Albums extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this.onClicks = this.onClicks.bind(this);
}
onClicks = () => {
console.log("lamus");
}
render () {
const albums = this.props.albums.map((album, i) => {
return (
<AlbumThumb name={album.name} img={album.photos[0].src} id={i} key={i} />
);
});
// console.log(albums);
console.log(this.onClicks);
return (
<div className="thumbContainer">{albums}</div>
)
}
}
const AlbumThumb = (props) => (
<div className="thumb">
<div className="thumbImgWrap">
<img src={require('./GalleryImages/' + props.img)} alt={props.name} />
</div>
<h3 className="thumbTitle">{props.name}</h3>
</div>
);
export default Albums;
This is Photos.js
import React from 'react';
import './forAlbum.css'
const Photos = (props) => {
const cliced = () => {
console.log("cliced");
}
const photos = props.photos.map(({ photos }) =>
<div>
<ul key={photos.id}>
{photos.id}
</ul>
{photos.map((eachThing, i) => {
return (
<PhotoMain name={eachThing.cap} img={eachThing.src} id={i} key={i} />
);
})}
</div>
);
// console.log(photos);
return <div className="thumbContainer" onClick={props.clicked}>{photos}</div>;
};
const PhotoMain = (props) => (
<div className="thumb" >
<div className="thumbImgWrap">
<img src={require('./GalleryImages/' + props.img)} alt={props.name} />
</div>
<h3 className="thumbTitle">{props.name}</h3>
</div>
);
export default Photos;
But i don't how to connect this, Maybe someone has an idea or suggestion?
I try to invoke this in next component GalleryPhotos.js
<Albums albums={data3} onClick={this.onClicks} />
<Photos photos={data3} />
const data3 = [
{
id: '1',
name: "Siatkówka",
photos: [
{
id: "11",
src: "siatkowka1.jpg",
cap: "Siatkówka"
},
{
id: "12",
src: "siatkowka2.jpg",
cap: "Siatkówka2"
},
{
id: "13",
src: "siatkowka3.jpg",
cap: "Siatkówka3"
}
]
},
{
id: '2',
name: "Piłka nożna",
photos:[
{
id: "21",
src: "pilkaNozna1.jpg",
cap: "Piłka nożna1"
},
{
id: "22",
src: "pilkaNozna2.jpeg",
cap: "Piłka nożna2"
},
{
id: "23",
src: "pilkaNozna3.jpg",
cap: "Piłka nożna3"
}
]
}
];
EDIT 1 - filter method
const Photos = (props) => {
const photos = props.photos.filter(photos => photos.id === '1').map(({photos}) =>
<div>
<ul key={photos.id}>
{photos.id}
</ul>
{photos.filter(eachThing => eachThing.id === eachThing.id).map((eachThing, i) =>
{
return (
<PhotoMain name={eachThing.cap} img={eachThing.src} id={i} key={i} />
);
})}
</div>
);
console.log(photos);
return <div className="thumbContainer">{photos}</div>;
};
I used the Filter.js method and thanks to it I am able to select by identifying the specific album ID, which photos must appear, but I am wondering how to set it as dynamic relative to the component. The biggest difficulty is understanding how the connections between components are made to make this filter effective. In addition, I wonder if the component Albums.js while filtering has something to logic
Edit 2:
Console message:
Uncaught TypeError: props.photos.filter is not a function
at Photos (Photos.js:6)
at mountIndeterminateComponent (react-dom.development.js:14592)
at beginWork (react-dom.development.js:15082)
at performUnitOfWork (react-dom.development.js:17903)
at workLoop (react-dom.development.js:17944)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
at invokeGuardedCallback (react-dom.development.js:250)
at replayUnitOfWork (react-dom.development.js:17224)
at renderRoot (react-dom.development.js:18037)
at performWorkOnRoot (react-dom.development.js:18919)
at performWork (react-dom.development.js:18826)
at performSyncWork (react-dom.development.js:18799)
at interactiveUpdates$1 (react-dom.development.js:19109)
at interactiveUpdates (react-dom.development.js:2328)
at dispatchInteractiveEvent (react-dom.development.js:5134)
The above error occurred in the <Photos> component:
in Photos (at GalleryPhotosVideos.js:208)
in div (at GalleryPhotosVideos.js:204)
in div (at GalleryPhotosVideos.js:196)
in CSSTransitionGroupChild (created by TransitionGroup)
in span (created by TransitionGroup)
in TransitionGroup (created by CSSTransitionGroup)
in CSSTransitionGroup (at GalleryPhotosVideos.js:190)
in GalleryPhotosVideos (created by Route)
in Route (at Content.js:33)
in Switch (at Content.js:24)
in div (at Content.js:23)
in Content (at App.js:14)
in div (at App.js:12)
in App (at src/index.js:10)
in Router (created by BrowserRouter)
in BrowserRouter (at src/index.js:10)
Uncaught TypeError: props.photos.filter is not a function
at Photos (Photos.js:6)
at mountIndeterminateComponent (react-dom.development.js:14592)
at beginWork (react-dom.development.js:15082)
at performUnitOfWork (react-dom.development.js:17903)
at workLoop (react-dom.development.js:17944)
at renderRoot (react-dom.development.js:18022)
at performWorkOnRoot (react-dom.development.js:18919)
at performWork (react-dom.development.js:18826)
at performSyncWork (react-dom.development.js:18799)
at interactiveUpdates$1 (react-dom.development.js:19109)
at interactiveUpdates (react-dom.development.js:2328)
at dispatchInteractiveEvent (react-dom.development.js:5134)
This message I see when I click
TypeError: props.photos.filter is not a function
const photos = props.photos.filter(photos => photos.id === photos.id).map(({photos}) =>
The component containing your Album and Photos should only render the Photos component if a state boolean value is true. When click on your album, this value will be updated :
import React, { Component } from 'react'
class ThankYou extends Component {
constructor(props) {
super(props)
this.state = {
showPhotos: false
}
}
albumClicked = ev => {
this.setState({ showPhotos: true })
}
render() {
return (
<>
<Albums albums={data3} onClick={this.albumClicked} />
{this.state.showPhotos && <Photos photos={data3} />}
</>
)
}
}
And then call the function passed in the album :
const AlbumThumb = (props) => (
<div className="thumb" onClick={ev => {props.onClick()}}> //Calls the parent function when clicked
<div className="thumbImgWrap">
<img src={require('./GalleryImages/' + props.img)} alt={props.name} />
</div>
<h3 className="thumbTitle">{props.name}</h3>
</div>
);
EDIT :
I did not notice that AlbumThumb wasn't your component. You will have to move the function up to the Album render function (and remove it from AlbumThumb) :
render() {
const albums = this.props.albums.map((album, i) => {
return (
<div onClick={ev => { props.onClick() }}>
<AlbumThumb name={album.name} img={album.photos[0].src} id={i} key={i} />
</div>
);
});
// console.log(albums);
console.log(this.onClicks);
return (
<div className="thumbContainer">{albums}</div>
)
}
EDIT 2 :
Filtering albums by owners name :
this.props.albums.filter(album => album.name.includes(myFilterString)).map(...
EDIT 3 :
Your parent class will have to be aware of wich album got selected, you will have to send your album data back to it using the onClick function :
const albums = this.props.albums.map((album, i) => {
return (
<div onClick={props.onClick(album)}>
<AlbumThumb name={album.name} img={album.photos[0].src} id={i} key={i} />
</div>
);
});
You can then tweak your parent class to store the whole selected album, and display photos depending on it :
class ThankYou extends Component {
constructor(props) {
super(props)
this.state = {
selectedAlbum: null
}
}
albumClicked = selectedAlbum => ev => {
this.setState({ selectedAlbum })
}
render() {
const { selectedAlbum } = this.state
return (
<>
<Albums albums={data3} onClick={this.albumClicked} />
{selectedAlbum && <Photos photos={data3.find(album => album.name === selectedAlbum.name)} />}
</>
)
}
}
Manage your data as state in an outer component as state. And pass it as props to both Album and Photos. Update photos from album component.
class Outer extends Component {
constructor(props) {
super(props)
this.state = {
photos: [],
albums: [
{
id: '1',
name: "Siatkówka",
photos: [
{
id: "11",
src: "siatkowka1.jpg",
cap: "Siatkówka"
},
{
id: "12",
src: "siatkowka2.jpg",
cap: "Siatkówka2"
},
{
id: "13",
src: "siatkowka3.jpg",
cap: "Siatkówka3"
}
]
},
{
id: '2',
name: "Piłka nożna",
photos:[
{
id: "21",
src: "pilkaNozna1.jpg",
cap: "Piłka nożna1"
},
{
id: "22",
src: "pilkaNozna2.jpeg",
cap: "Piłka nożna2"
},
{
id: "23",
src: "pilkaNozna3.jpg",
cap: "Piłka nożna3"
}
]
}
]
}
}
const updatePhotos = (albumId) => {
// pass this function to album as prop and bind with each album.
const album = this.state.albums.filter((album) => album.id === albumId)
this.setState({
photos: album.photos
})
}
render() {
<>
<Albums albums={this.state.albums} clickHandler={this.updatePhotos} />
{this.state.photos ? <Photos photos={this.state.photos} /> : null}
</>
}
}
In Albums, call clickHandler with album id
<AlbumThumb name={album.name}
img={album.photos[0].src}
id={i}
key={i}
onClick={() => this.props.clickHandler(album.id)} />
I'm follow the steps of this dependencie:
http://jossmac.github.io/react-images/
And it isn't work. No picture showing and there is showing an error message:
index.js:2178 Warning: Failed prop type: The prop onClose is marked
as required in Lightbox, but its value is undefined
Here is my code:
import React, { Component } from "react";
import Lightbox from "react-images";
const URL_INTERIORES = "http://localhost:3001/interiores";
const LIGHTBOX_IMAGE_SET = [
{
src: "/images/int_02.jpg",
caption: "A forest",
// As an array
srcSet: ["/images/int_02.jpg", "/images/int_02.jpg"]
},
{
src: "/images/int_02.jpg",
// As a string
srcSet: "/images/int_02.jpg 1024w, /images/int_02.jpg 800w, /images/int_02.jpg 500w, /images/int_02.jpg 320w"
}
];
class Interiores extends Component {
render() {
const { open } = this.state;
return (
<div>
<div>
<Lightbox
images={LIGHTBOX_IMAGE_SET}
isOpen={this.state.lightboxIsOpen}
onClickPrev={this.gotoPrevLightboxImage}
onClickNext={this.gotoNextLightboxImage}
onClose={this.closeLightbox}
/>
</div>
</div>
);
}
}
export default Interiores;
Does anybody know how to solve it? Tahnk you
Consider adding all the missing handlers & state in your class:
class Interiores extends Component {
state = {
lightboxIsOpen: false
}
gotoPrevLightboxImage() {
// Add the logic here
}
gotoNextLightboxImage() {
// Add the logic here
}
closeLightbox(e) {
// Add the logic here
}
render() {
const { lightboxIsOpen } = this.state;
return (
<div>
<Lightbox
images={LIGHTBOX_IMAGE_SET}
isOpen={lightboxIsOpen}
onClickPrev={() => this.gotoPrevLightboxImage()}
onClickNext={() => this.gotoNextLightboxImage()}
onClose={e => this.closeLightbox(e)}
/>
</div>
);
}
}