SeN
SeN

Reputation: 161

How to pass props onClicked function in one component to another

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}) => 

Upvotes: 1

Views: 433

Answers (2)

Treycos
Treycos

Reputation: 7492

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)} />}
            </>
        )
    }
}

Upvotes: 3

Nafees Anwar
Nafees Anwar

Reputation: 6598

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)}  />

Upvotes: 0

Related Questions