How to join an array with folder images in React - arrays

I am trying to render a child component with images from local folder, but I don't know how to do it.
So I have a const array with details about several projects. Each of the project has its own folder with images. The project name is equal folder name with images
Parent component
import { myProjects } from '../lib/Projects'; //its array with projects
export default class Parent extends Component {
render() {
// function for images
function importAll(r) {
return r.keys().map(r);
}
const projectA = importAll(require.context('../../assets/images/projectA', false, /\.(png|jpe?g|svg)$/));
const projects = myProjects.map((project, i) =>
<Child id={i} key={i} project={project} />)
return (
<div className="main-container">
{projects}
</div>
)
}
}
Child component
export default class Child extends Component {
render() {
const { project } = this.props;
return (
<div className="item">
<div className="desc">
<div className="item-name">
<p>{project.name}</p>
</div>
<div className="item-description">
<p>{project.description}</p>
</div>
<div className="item-tools">
<p>{project.tools}</p>
</div>
</div>
// this part works well
// How to make below part work?
<div className="image-block">
<div className="item-image-first">
<img src={project.name[0]} alt=""/>
</div>
<div className="item-images">
{project.name ? project.name.map((image, index) => {
return (
<div className="image-block-small" key={index}>
<ModalImage
small={image}
large={image}
alt=""
hideDownload={true}
hideZoom={true}
className="modal-image"
/>
</div>
)
})
: null }
</div>
</div>
</div>
)
}
}
Maybe there is a way to add an extra array here?
const projects = myProjects.map((project, i) =>
<Child id={i} key={i} project={project} />)
Any suggestion?

Related

React) How to return to the main page

The toBack() function worked well in the local environment, but the page cannot be found after deployment to netlify.
How should I write the code?
class Itemdetail extends Component {
toBack = () => {
window.location.replace("/main");
};
render() {
const { name, description, qr_link } = this.props.item;
return (
<div className={styles.item_box}>
<div className={styles.item_box_inner}>
<div className={styles.qr_box}>
<img src={qr_link} alt="qr_link" />
</div>
<div className={styles.text_box}>
<p className={styles.name}>{name}</p>
<p className={styles.description}>{description}</p>
<div onClick={this.toBack} className={styles.back_btn}>
Go back
</div>
</div>
</div>
</div>
);
}
}

How to add the image folders to component that render an array in React

I asked a question here How to join an array with folder images in React, but didn't get any help.
So I was trying to change the logic, unfortunately useless.
I have Parent component with an array. This child component should render that array and somehow images from local folder. Folder name equal project.image.
Child component
export default class Child extends Component {
render() {
const { project } = this.props;
function importAll(r) {
return r.keys().map(r);
}
const folder1 = importAll(require.context('../../assets/images/folder1',false,/\.(png|jpe?g|svg)$/));
const folder2 = importAll(require.context('../../assets/images/folder2',false,/\.(png|jpe?g|svg)$/));
return (
<div className="portfolio-item">
<div className="desc">
<div className="item-name">
<p>{project.name}</p>
</div>
<div className="image-block">
<div className="item-images">
<Carousel showArrows={true} showThumbs={false} >
// attempt 1 (this works fine, but it's hurdcoded ... so it's not a solution )
{project.image === 'folder1' ? folder1.map((image, index) => {
return (
<div className="image-block-small" key={index}>
<div>
<img src={image} alt=""/>
</div>
</div>
)})
: null}
</Carousel>
</div>
// attempt 2 (Here project.image equal folder1 (folder name), but here I get error "TypeError: webpack_require(...).context is not a function", because the arguments passed to require.context must be literals!)
{importAll(require.context('../../assets/images/' + project.image, false, /\.(png|jpe?g|svg)$/)).map((image, index) => {
return (
<div className="image-block-small" key={index}>
<div>
<img src={image} alt=""/>
</div>
</div>
)})
: null}
</Carousel>
</div>
I tried even to make it like a variable
const folder1 = '../../assets/images/folder1';
{importAll(require.context(folder1, false, /\.(png|jpe?g|svg)$/)).map((image, index) => { ... }
but got the same response as was in the second attempt.
Any help will be appreciated.
Unfortunately, I didn't get any answers to my question. So I've solved it using switch and extra component.
Images component
function importAll(r) {
return r.keys().map(r);
}
const folder1 = importAll(require.context('../../assets/images/folder1', false, /\.(png|jpe?g|svg)$/));
const folder2 = importAll(require.context('../../assets/images/folder2', false, /\.(png|jpe?g|svg)$/));
const folder3 = importAll(require.context('../../assets/images/folder3', false, /\.(png|jpe?g|svg)$/));
export default class Images extends Component {
selectFolder(param) {
switch(param) {
case 'folder1':
return folder1;
case 'folder2':
return folder2;
// etc ....
default:
return folder3 ;
}
}
render() {
return (
<div className="item-images">
<Carousel showArrows={true} showThumbs={false} >
{this.selectFolder(this.props.param).map((image, index) => {
return (
<div className="image-block-small" key={index}>
<img src={image} alt=""/>
</div>
)
})
}
</Carousel>
</div>
)
}
}
Add put it with props "image" that equal to "folder name" inside Child component
<div className="image-block">
<ProjectImages param={project.image}/>
</div>
Hope it will help someone else.

How to pass Mobx store as props to react compoent

I have this app that uses mobx, in it there is a component called "Listings" that uses some state from mobx to render a list of items.
The way it is right now, is that the Listings component gets the data it needs(store.restaurantResults[store.selectedFood]) from inside of it by using the mobx store like so:
const Listings = () => {
const store = React.useContext(StoreContext);
return useObserver(() => (
<div className="pa2">
{store.restaurantResults[store.selectedFood] &&
store.restaurantResults[store.selectedFood].map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<p>{rest.name}</p>
</div>
);
})}
</div>
));
};
But i think this is wrong, as it couples the component with the data, I want instead to pass that data via props so it can be reusable.
What is the correct way to do this? Right now my App looks like this, where it's being wrapped around a storeProvider:
function App() {
return (
<StoreProvider>
<div className="mw8 center">
<Header title="EasyLunch" subTitle="Find Pizza, Burgers or Sushi in Berlin the easy way"/>
<FixedMenu menuItem1={"Pizza"} menuItem2={"Burger"} menuItem3={"Sushi"} />
<p className="b tc pt3">or...</p>
<Search />
<Listings />
</div>
</StoreProvider>
);
}
My idea is to extract everrything inside the StoreProvider into another component that has a store and returns the jsx via useObserver so that I can acces the store and then pass what i need as props to the other components. like this:
const Wapper = () => {
const store = React.useContext(StoreContext);
return useObserver(() => (
<div className="mw8 center">
<Header title="EasyLunch" subTitle="Find Pizza, Burgers or Sushi in Berlin the easy way" />
<FixedMenu menuItem1={"Pizza"} menuItem2={"Burger"} menuItem3={"Sushi"} />
<p className="b tc pt3">or...</p>
<Search />
<Listings listings={store.restaurantResults[store.selectedFood]} />
</div>
))
}
And then on the listings component change the hard coded store.restaurantResults[store.selectedFood] inside to use the props that is being passes now, that is called listigs like so:
const Listings = ({listings}) => {
const store = React.useContext(StoreContext);
return useObserver(() => (
store.loading
? <Loading />
: <div className="pa2">
<div className="flex flex-wrap">
{listings &&
listings.map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<img className='object-fit' src={rest.image_url} alt="restuarant" />
<p>{rest.name}</p>
<p>{rest.location.address1}</p>
</div>
);
})}
</div>
</div>
));
};
And this works, but is this the right way to go about this?
As <Listings/> can be provided with listing and loading you can:
const Listings = ({listings, loading}) => {
if(loading) return <Loading />
return (
<div className="pa2">
<div className="flex flex-wrap">
{listings && listings.map((rest, i) => {
return (
<div key={i} className="pa2 listing">
<img className='object-fit' src={rest.image_url} alt="restuarant" />
<p>{rest.name}</p>
<p>{rest.location.address1}</p>
</div>
);
})}
</div>
</div>
);
}
No observables used, no useObservable required.
You want to useObservables on store for listings then no reason to wrap all components with useObservable. You should wrap <Listings/> only.
I usually define my store as a global, so every component has visibility of it:
class Store {
#observable myVar
}
global.store = new Store()
And in my components i just use it:
#observer
export default class MyComponent extends React.Component {
constructor () {
super()
store.myVar = 0
}
setMyVar (a) {
store.myVar += 1
}
render () {
return <button onClick={this.setMyVar}>
Clicked {store.myVar} times
</button>
}
}

Can't display mapped posts from an API using axios inside react component

I would like to show mapped posts from an API inside the OwlCarousel component (import OwlCarousel from 'react-owl-carousel') the code works just fine, but only outside the OwlCarousel component. You can test on this CodeSandbox https://codesandbox.io/s/friendly-rhodes-bv5ot, the code works when you remove the OwlCarousel tag.
renderPost = () => {
return this.state.posts
? this.state.posts.map(data => (
<div key={data.id} className="item">
<div className="heading">{data.subject}</div>
<div className="content">{data.message}</div>
</div>
))
: "Loading...";
};
render() {
return (
<div className="container">
<OwlCarousel className="owl-container owl-theme">
{this.renderPost()}
</OwlCarousel>
</div>
);
}
The code works only when i put the function outside the OwlCarousel component, i think it has something to do with scopes!
render() {
return (
<div className="container">
{this.renderPost()}
</div>
);
}
Try with following code
renderPost = () => {
return (
<div>
{this.state.posts
? this.state.posts.map(data => (
<div key={data.id} className="item">
<div className="heading">{data.subject}</div>
<div className="content">{data.message}</div>
</div>
))
: "Loading..."}
</div>
)
};
And In your render of the Component, you can do same as you have already done,
{this.renderPost()}

ReactJS product id is not defined

I have the problem when I use the Reactjs, I'm really new to Reactjs, so maybe it's a easy problem:
class Product extends Component{
handleUpVote() {
this.props.onVote(this.props.id)
}
render(){
return(
<div className='item'>
<div className='middle aligned content'>
<div className='header'>
<a onClick={this.handleUpVote}>
<i className='large caret up icon'></i>
</a>
{this.props.votes}
</div>
</div>
</div>
)
}
}
class ProductList extends Component {
handleProductUpVote(prductId){
console.log(productId +' was upvoted')
}
render() {
const products1 = Data.sort((a,b) => (
b.votes-a.votes
));
const products=products1.map((product) =>{
return (
<div className='ui items'>
<Product
key={'product-'+product.id}
id={product.id}
onVote={this.handleProductUpVote}
/>
</div>
)})
return (
<div className='ui items'>
{products}
</div>
)
}}
export default ProductList;
At this line I am getting the error and i cant understand why:
this.props.onVote(this.props.id)
Forget binding this.
You need to pass the ID as a parameter to your click handler function.
Something like this:
class Product extends Component{
handleUpVote(id) {
this.props.onVote(id)
}
...
<Product
key={'product-'+product.id}
id={product.id}
onVote={() => this.handleProductUpVote(product.id)}
/>
}

Resources