Trouble loading an objects src in ReactJS - reactjs

I am still a bit new to React and posting on this forum so please bear with me. I currently have two React files which I believe are talking to each other, but there seems to be a disconnect when trying to pull information from an object. One of my React files is:
import React, { Component } from 'react';
import './App.css';
export class App extends React.Component {
render() {
const src = this.props.src;
const alt = this.props.alt;
const width = this.props.width;
const height = this.props.height;
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Will''s weird online shop thing I have no idea about</h1>
</header>
<p className="App-intro">
Click the arrows to browse through the different items.
</p>
<img src={src} alt={alt} width={width} height={height} />
</div>
);
}
}
export default App;
and the other is :
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import {App} from './App';
import registerServiceWorker from './registerServiceWorker';
import dogbag from './images/dogbag.jpg';
const DogBagObj = {
src: dogbag,
alt: 'Cute dog handbag',
height: '100px',
width: '70px'
};
const Items = [
DogBagObj,
'https://i.pinimg.com/736x/0b/f4/bd/0bf4bd031a363fc68b56afe6289f450f--random-pokemon-pokemon-stuff.jpg',
'https://pbs.twimg.com/profile_images/881211588748988416/zQL9OLuc_400x400.jpg',
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Sun-crypto-accelerator-1000.jpg/1200px-Sun-crypto-accelerator-1000.jpg'
]
class OnlineStore extends React.Component {
constructor(props) {
super(props);
this.state = { currentItem: 0 };
this.interval = null;
this.changeItem = this.changeItem.bind(this);
}
changeItem() {
let current = this.state.currentItem;
let next = ++current % Items.length;
this.setState({ currentItem: next });
}
componentDidMount() {
this.interval = setInterval(this.changeItem, 1000);
}
render() {
const src = Items[this.state.currentItem];
return <App src={src} />;
}
}
ReactDOM.render(
<OnlineStore />,
document.getElementById('root'));
registerServiceWorker();
I am confident that I have correctly imported the dogbag.jpg from the image folder and the three images which have direct links to them load correctly.
I feel like my problem lies within getting the DogBagObj.src to correctly read. If I change DogBagObj in the Items array to dogbag it will load the image but I would also like the ability to control multiple tags for each image (such as the alt, height and width). Is there some minor syntax error I am over looking or is this a problem which would be much harder to remedy? Thank you for your time.

Your items array contains multiple data structure but you treat it as if it contains only one.
Either use strings only or objects only.
For example..
Strings only:
const Items = [
DogBagObj.src,
'https://i.pinimg.com/736x/0b/f4/bd/0bf4bd031a363fc68b56afe6289f450f--random-pokemon-pokemon-stuff.jpg',
'https://pbs.twimg.com/profile_images/881211588748988416/zQL9OLuc_400x400.jpg',
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Sun-crypto-accelerator-1000.jpg/1200px-Sun-crypto-accelerator-1000.jpg'
]
Or use objects with similar data structure:
const Items = [
DogBagObj,
{src:'https://i.pinimg.com/736x/0b/f4/bd/0bf4bd031a363fc68b56afe6289f450f--random-pokemon-pokemon-stuff.jpg'},
{src:'https://pbs.twimg.com/profile_images/881211588748988416/zQL9OLuc_400x400.jpg'},
{src:'https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Sun-crypto-accelerator-1000.jpg/1200px-Sun-crypto-accelerator-1000.jpg'}
]
And in your render method:
render() {
const src = Items[this.state.currentItem].src;
return <App src={src} />;
}

Related

Error adding Google Maps with react - TypeError: Cannot read property 'maps' of undefined

// App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import Map from "./Map.js"
class App extends React.Component {
constructor(props) {
super(props);
this.loadScript = this.loadScript.bind(this);
}
loadScript() {
const API_KEY = process.env.REACT_APP_API_KEY;
const url = `https://maps.googleapis.com/maps/api/js?key=${API_KEY}&libraries=places`;
const s = document.createElement("script");
s.src = url;
document.head.appendChild(s);
}
componentWillMount() {
this.loadScript();
}
render() {
return (
<div>
<Map />
</div>
);
}
}
export default App;
//Map.js
import React from "react"
export default class Map extends React.Component {
constructor(props) {
super(props);
this.loadMap = this.loadMap.bind(this);
}
loadMap() {
const map = new window.google.maps.Map(document.getElementById('map'), {
center: { lat: -34.397, lng: 150.644 },
zoom: 8
});
}
componentWillMount() {
this.loadMap();
}
render() {
return (
<div id="map" style={{ width: 100, height: 100 }}></div>
);
}
}
Hi there, I am totally new to React, I am trying to load Google Maps without the help of a third-party library.
I have dynamically created a script tag and inserted it into the DOM. I am getting this error, trying to access the variables in the script.
My guess is that 'maps' is being accessed before the script is loaded. I am lost, on how to fix this error.
When you load a script programmatically you can listen for "onload" event and do the rest of your logic when the script will be loaded. In this case, your loadScript function might look like this:
loadScript() {
const API_KEY = process.env.REACT_APP_API_KEY;
const url = `https://maps.googleapis.com/maps/api/js?key=${API_KEY}&libraries=places`;
const s = document.createElement("script");
s.src = url;
document.head.appendChild(s);
s.onload = function(e){
console.info('googleapis was loaded');
}
}
You can add a scriptLoaded state to your App component and change it in the onload function, in this case, you need to render only if scriptLoaded is true :
<div>
{this.state.scriptLoaded && <Map />}
</div>

Why the data not displayed in nextjs?

I am making a very very simple nextjs application where I am trying to fetch the data from api.
My requirement is I should display the data in layout.js file and this layout.js file is a children in index.js file.
index.js:
import Layout from "./layout";
import React from "react";
class Home extends React.Component {
render() {
return (
<div>
<Layout />
<h4> Main content will be displayed here !! </h4>
</div>
);
}
}
export default Home;
layout.js:
import React from "react";
import fetch from "isomorphic-unfetch";
function Layout(props) {
return (
<div>
<p>Preact has {props.stars} ⭐</p>
<p> Why I couldn't get the above "props.star" ? </p>
</div>
);
}
Layout.getInitialProps = async () => {
console.log("comes into layout getinitial props");
const res = await fetch("https://api.github.com/repos/developit/preact");
const json = await res.json(); // better use it inside try .. catch
return { stars: json.stargazers_count };
};
export default Layout;
So as per the above given code, I have called the layout page inside index.js page (in my real application I need to call like this only so no changes in calling layout inside index)..
But when I made a console.log() in the function Layout.getInitialProps in layout, it doesn't print anything and hence the api data not fetched..
Complete working demo here with code
Why can't I fetch the data inside the layout.js while calling as a children from index.js?
Also provide me the right updated solution to achieve this.. I really searched for many questions but none solved my issue and I couldn't understand those solutions clearly so please help me with the above given example.
That because getInitialProps can only be added to the default component exported by a page, adding it to any other component won't work.
You should use componentDidMount() or useEffect instead, or move getInitialProps in the index and then pass the result to the component. something like (not tested) :
index.js :
import Layout from "./layout";
import React from "react";
class Home extends React.Component {
render() {
return (
<div>
<Layout />
<h4> Main content will be displayed here !! </h4>
</div>
);
}
}
export default Home;
layout.js
import React from "react";
import fetch from "isomorphic-unfetch";
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
stars: false
};
}
async componentDidMount() {
console.log("comes into layout getinitial props");
const res = await fetch("https://api.github.com/repos/developit/preact");
const json = await res.json(); // better use it inside try .. catch
this.setState({ stars: json.stargazers_count });
}
render() {
const { stars } = this.state;
return (
<div>
<p>Preact has {stars} ⭐</p>
<p> Why I couldn't get the above "props.star" ? </p>
</div>
);
}
}
export default Layout;
Edit:
Example with class component
Bonus: If you want to add the layout for all the pages of your app this isn't the best approach, instead you should take a look to custom _app.js, example

Is this only possible with external URLs and not local?

I'm trying to make a photo gallery using react-images, the URLs are correct but the photos themselves are not loading into my web app. I get the broken image icon when switching themodalIsOpen:false to true.
Ive tried looking up examples of the same problems and alternatives, like if the component was configured right or if I am extending it right in the class.
import React, { Component } from 'react';
import Carousel, { Modal, ModalGateway } from 'react-images';
import blksmith from '../images/gallery/illustration/Blacksmith.jpg';
import mage from '../images/gallery/illustration/Mage.jpg';
const images =
[
{
src:{blksmith}
} ,
{
src:{mage}
}
];
class illuGallery extends Component {
state = { modalIsOpen: false }
toggleModal = () => {
this.setState(state => ({ modalIsOpen: !state.modalIsOpen }));
}
render() {
const { modalIsOpen } = this.state;
return (
<ModalGateway>
{modalIsOpen ? (
<Modal onClose={this.toggleModal}>
<Carousel
views={images}
/>
</Modal>
) : null}
</ModalGateway>
);
}
}
export default illuGallery;
This is in the actual gallery.js file, the web page that renders the gallery.
import React from 'react';
import Layout from "../components/layout";
import IlluPhotos from "../components/illustrationGallery";
import SEO from "../components/seo";
import './gallery.scss';
const GalleryPage = () => {
return (
<Layout>
<div style={{width:'100%',height:'250px'}}>
<SEO title="Gallery" />
<IlluPhotos/>
</div>
</Layout>
)
}
export default GalleryPage;
I am seeking some feedback on how to get this to work and what I did wrong, or what I should explore more.
So I ended up adding the pictures I wanted for the gallery to the public folder as mentioned farther down in this post
Since the https://localhost:8000 was appearing in front of the links to the images I wanted to use.
Thank you all for helping me find the answer!!
You don't need to import images.
According to react-images documentation, you just need to pass path to image as a string to <Carousel> component, like in this example below:
import React from 'react';
import Carousel from 'react-images';
const images = [{ src: 'path/to/image-1.jpg' }, { src: 'path/to/image-2.jpg' }];
class Component extends React.Component {
render() {
return <Carousel views={images} />;
}
}

Dynamically importing components in ReactJS

I have just been getting my hands dirty with react-js and have come across this piece of code for dynamically importing components in my app which I cant seem to understand?
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Dynamic extends Component {
constructor(props) {
super(props);
this.state = { module: null };
}
componentDidMount() {
const { path } = this.props;
import(`${path}`)
.then(module => this.setState({ module: module.default }))
}
render() {
const { module: Component } = this.state; // Assigning to new variable names #see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
return(
<div>
{Component && <Component />} // the code i can't figure out
//{Component} works fine too
//{<Component />} gives error
</div>
)
}
}
ReactDOM.render(<Dynamic path='./FirstComponent' />, document.getElementById('root'));
Can someone please explain the line of code which i have highlighted it looks to me some kind of conditional rendering but as far as i know it works like if the left hand evaluates to true the right hand is rendered but why is this code working with only {Component} as well?
Because at initial render {Component} evaluates to null.
As you have used destructuring.
const { module: Component } = this.state;
so
Component = null
But when you use <Component/> at initial render there is no <Component/> component. So using { <Component />} gives error.
Using Component and <Component/> are different.

How to use axios result in various react classes

I have basically an html document with various DOM elements that I want to fill with data coming from react.
<html> ....
<div id="value1">
....
<div id="value2">
</html>
Then I have a index.js file that associates each dom element with a (different) react class:
import ClassName1 from ?...?;
ReactDOM.render(<ClassName1 />, document.getElemnentById('value1'));
No I have a React class that does something like that:
class ClassName1 extends Component
constructor()
...
componentDidMount()
axios-call
=> return value1,value2
What I want to achieve is
render(value1 => DOM(1) , value2 => DOM(2))
What you want to do doesn't seem like something you'd want to use react for. But I'll give you two scenarios:
Scenario 1: You want two "child components" to render with different values from what you got from the axios call.
The best solution for this is just to render two different components, like so:
class Foo extends React.Component {
constructor() {
this.state = {
value1: null,
value2: null,
};
}
componentDidMount() {
axios(someUrl).then(response => {
const value1 = response.body.value1;
const value2 = response.body.value2;
this.setState({ value1, value2 });
});
}
render() {
return(
<React.Fragment>
<div id="value1">{value1}</div>
<div id="value2">{value2}</div>
</React.Fragment>
);
}
}
Scenario 2: You want to change other DOM elements that are not part of the react tree.
In this case, you could get the DOM elements by their ID and change the content when the axios call returns, something like this:
class Foo extends React.Component {
constructor() {
this.state = {
value1: null,
value2: null,
};
}
componentDidMount() {
axios(someUrl).then(response => {
const value1 = response.body.value1;
const value2 = response.body.value2;
this.setState({ value1, value2 });
const element1 = document.getElementById('value1');
element1.innerHTML = value1;
const element2 = document.getElementById('value2');
element2.innerHTML = value2;
});
}
render() {
return(null);
}
}
In scenario 2, you'd be changing stuff outside of react tree... which is unconventional, but it seems to be what you're asking for. Remember that you'll need divs with value1 and value2 ids in your DOM before the axios call returns with values.
Simple answer (but bad) - You can simply render twice in different root as shown below.
import React from "react";
import ReactDOM from "react-dom";
function App({ value }) {
return <div className="App">{value}</div>;
}
const root1 = document.getElementById("root1");
ReactDOM.render(<App value="value1" />, root1);
const root2 = document.getElementById("root2");
ReactDOM.render(<App value="value2" />, root2);
But the problem is that, now those two components aren't in the same React tree, thus can't communicate with each other.
If you need a central container that retrieves data but want to pass data, you can use React Portal in v16+.
You can do something crazy like this with Portal.
Suppose that you want to pass value1 & value2 to following divs.
<body>
<div id="root"></div>
<div id="value1">
<div id="value2">
...
</body>
where root div is main React tree is mounted on.
You can create a portal by mounting onto those value1&2 divs like following.
import React, { Component } from "react";
import ReactDOM from "react-dom";
class ValuePortal extends Component {
constructor(props) {
super(props);
this.el = document.getElementById(props.elementID);
}
render() {
return ReactDOM.createPortal(this.props.value, this.el);
}
}
function App() {
return (
<div className="App">
<ValuePortal elementID="value1" value="for value1" />
<ValuePortal elementID="value2" value="for value2" />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Your main container is mounted in the root as shown above and values are displayed using portal component, ValuePortal.
You can follow along on CodeSandBox.

Resources