I have this URL that is feched succefully by Axios
const URL_INTERIORES = 'http://localhost:3001/interiores';
I installed the react-image-lightbox from npm and it gave to me default images configured in array.
const images = [
'//placekitten.com/1500/500',
'//placekitten.com/4000/3000',
'//placekitten.com/800/1200',
'//placekitten.com/1500/1500',
];
I would like to change the default array to get the images from the db.json file to come into images's lightbox. How can I solve it?
Here is the rest of the code, with the 'react-image-lightbox' configuration:
class Interiores extends Component {
constructor(props) {
super(props)
this.state = {
interiores: [],
photoIndex: 0,
isOpen: false
}
}
componentDidMount() {
axios.get(URL_INTERIORES)
.then(res => {
this.setState({ interiores: res.data })
})
}
render() {
const { photoIndex, isOpen } = this.state;
return (
<div>
<button type="button" onClick={() => this.setState({ isOpen: true })}>
Open Lightbox
</button>
{isOpen && (
<Lightbox
mainSrc={images[photoIndex]}
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>
)
}
}
export default Interiores;
And here is my db.json file.
"interiores": [
{
"text": "introduction text here",
"images": [
"int_01_thumb.jpg", "int_02_thumb.jpg", "int_03_thumb.jpg",
"int_04_thumb.jpg", "int_05_thumb.jpg", "int_06_thumb.jpg",
"int_07_thumb.jpg", "int_08_thumb.jpg", "int_09_thumb.jpg"
]
}
],
I've never worked with such library, so I might be missing something, but would an alternative like this work?
render() {
const { interiores, photoIndex, isOpen } = this.state; // Added 'interiores'
// Link to static root and make a relative path for each iamge
const staticRoot = '//localhost:3001/interiores/'
const images = interiores[0].images.map(i => staticRoot + i)
// Rest of your code
}
Once you have the file names, just link them to your static files/images path and map over the image array.
Related
I'm implementing a Like and Dislike Button, and I wanna that when I click them will be with other colors, but just the clicked component, when I click all buttons change the state, can anybody help me?
`
const indexPost = async () => {
const data = await api.get('/api/posts')
if(data.data.length !=0){
const dataArray = data.data
if(dataArray.length === 0) {
return
}else{
return(
setPost(dataArray.map( data => (
<Post key={data._id} id={data._id} title={data.title} text={data.text}>
<Like id={data._id}></Like>
</Post>
)))
)
}
}
}
export default function Like({itemId}) {
const context = useContext(notificationContext)
const {isLoved, Like, Loved, Unlike, isLike, isUnlike, setIsLike, setIsUnlike, setIsLoved } = context
return(
<div className={styles.likeContainer} key={itemId}>
{isLike ? (
<button className={styles.likeContent} onClick={() => setIsLike(false)}><Icon.ThumbsUp className={styles.Icon} fill="#5CB0BB" ></Icon.ThumbsUp></button>) :
(<button className={styles.likeContent} onClick={() => Like() }><Icon.ThumbsUp className={styles.Icon} ></Icon.ThumbsUp></button>)}
{isLoved ?
(<button className={styles.likeContent} onClick={() => setIsLoved(false)}><Icon.Heart className={styles.Icon} fill="red" ></Icon.Heart> </button>) :
(<button className={styles.likeContent} onClick={() => Loved() }><Icon.Heart className={styles.Icon} ></Icon.Heart></button>)}
{isUnlike ? (
<button className={styles.likeContent} onClick={() => setIsUnlike(false)}><Icon.ThumbsDown className={styles.Icon} fill="#702BA6" ></Icon.ThumbsDown> </button>) :
(<button className={styles.likeContent} onClick={() => Unlike()}><Icon.ThumbsDown className={styles.Icon} ></Icon.ThumbsDown></button>
)}
</div>
)
};
I have implemented the similar one in my project, it is very basic , it shows how to update the likes , you need to handle the cases of user authentication and stuff
App.js
import { useState, useEffect, createContext, useReducer } from "react";
import { updateArrayOfObj } from "./utils";
import AllPosts from "./AllPosts";
export const PostsContext = createContext();
const initialState = {
posts: [
{
_id: "1",
name: "Browny",
image: "http://placekitten.com/200/310",
likes: 0,
love: 0,
dislikes: 0
},
{
_id: "2",
name: "Blacky",
image: "http://placekitten.com/200/320",
likes: 0,
love: 0,
dislikes: 0
},
{
_id: "3",
name: "SnowWhite",
image: "http://placekitten.com/200/300",
likes: 0,
love: 0,
dislikes: 0
}
]
};
const reducer = (state, action) => {
switch (action.type) {
case "UPDATE_POST":
return {
...state,
posts: updateArrayOfObj(
state.posts,
action.payload.obj,
"_id",
action.payload._id
)
};
case "CREATE_POST":
return {
...state,
posts: [...state.posts, ...action.payload.data]
};
case "DELETE_POST":
return {
...state,
posts: state.posts.filter((ele) => ele._id !== action.payload._id)
};
default:
return state;
}
};
export default function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<PostsContext.Provider
value={{
state,
dispatch
}}
>
<div className="App">
<AllPosts />
</div>
</PostsContext.Provider>
);
}
PostsAll.js
import Post from "./Post";
import { PostsContext } from "./App";
import { useContext } from "react";
export default function AllPosts() {
const { state } = useContext(PostsContext);
return (
<div className="allPosts">
{state.posts.map((item) => {
return (
<Post
name={item.name}
image={item.image}
likes={item.likes}
love={item.love}
dislikes={item.dislikes}
id={item._id}
key={item._id}
/>
);
})}
</div>
);
}
Post.js
import { PostsContext } from "./App";
import { useContext } from "react";
export default function Post(props) {
const { state, dispatch } = useContext(PostsContext);
const handleUserInteraction = (type, id) => {
dispatch({
type: "UPDATE_POST",
payload: {
obj: { [type]: props[type] + 1 },
_id: id
}
});
};
return (
<div className="post">
<h3>{props.name}</h3>
<img src={props.image} alt="cat" />
<br />
<button onClick={() => handleUserInteraction("likes", props.id)}>
{props.likes} Like
</button>{" "}
<button onClick={() => handleUserInteraction("love", props.id)}>
{props.love} Love
</button>{" "}
<button onClick={() => handleUserInteraction("dislikes", props.id)}>
{props.dislikes} Dislike
</button>
</div>
);
}
You can refer to this codesandbox to implement the same
You can use onClick() on each like button and attach it with a function, then you can get the value of that particular like with e.currentTarget.id and change its css/style the way you want.
const handleClick=(e)=>
{
console.log(e.currentTarget.id);
}
Iam using Ant Design for React Js UI. Am using Tree component to show up in the list. I also have 2 button to expand and collapse the Tree list. I use the defaultExpandAll prop to manage this.
On the expand and collapse button click i set a bool to true and false respectively.
Button it doesn't expand on the button click.
If I set True initially to that flag state it works.
Is there any work Around.
I have 2 components. (Expand and collapse button are in parent component)
**Parent Component**
setExpandOrCollapse(value) {
this.setState({ expandOrCollapse: value });
}
<HeaderRow>
<Button onClick={() => this.setExpandOrCollapse(true)}>Expand All</Button>
<Button onClick={() => this.setExpandOrCollapse(false)}>Collapse All</Button>
</HeaderRow>
<Card>
{ItemTree && (ItemTree.length > 0) ? (
<ItemTree
dataSource={ItemTree}
expandOrCollapse={expandOrCollapse}
/>
) : null }
</Card>
**Child Component**
<Tree
draggable={isDraggable}
defaultExpandAll={expandOrCollapse}
>
{loopitemNodes(dataSource)}
</Tree>
dataSource is obtained from Redux api call.
Is there any work around.
The states in Ant design which are prefixed with default only work when they are rendered for the first time (and hence the default).
For working out programmatic expand and collapse, you need to control the expansion of tree using expandedKeys and onExpand props.
import { flattenDeep } from "lodash";
class Demo extends React.Component {
state = {
expandedKeys: []
};
constructor(props) {
super(props);
this.keys = this.getAllKeys(treeData);
}
getAllKeys = data => {
// This function makes an array of keys, this is specific for this example, you would have to adopt for your case. If your list is dynamic, also make sure that you call this function everytime data changes.
const nestedKeys = data.map(node => {
let childKeys = [];
if (node.children) {
childKeys = this.getAllKeys(node.children);
}
return [childKeys, node.key];
});
return flattenDeep(nestedKeys);
};
onExpand = expandedKeys => {
console.log("onExpand", expandedKeys);
// if not set autoExpandParent to false, if children expanded, parent can not collapse.
// or, you can remove all expanded children keys.
this.setState({
expandedKeys
});
};
renderTreeNodes = data =>
data.map(item => {
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{this.renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode key={item.key} {...item} />;
});
expandAll = () => {
this.setState({
expandedKeys: this.keys
});
};
collapseAll = () => {
this.setState({
expandedKeys: []
});
};
render() {
return (
<Fragment>
<button onClick={this.expandAll}>Expand All</button>
<button onClick={this.collapseAll}>Collapse All</button>
<Tree onExpand={this.onExpand} expandedKeys={this.state.expandedKeys}>
{this.renderTreeNodes(treeData)}
</Tree>
</Fragment>
);
}
}
Codesandbox
class Demo extends React.Component {
state = {
expandedKeys: ["0-0-0", "0-0-1"],
autoExpandParent: true,
selectedKeys: []
};
onExpand = expandedKeys => {
console.log("onExpand", expandedKeys);
// if not set autoExpandParent to false, if children expanded, parent can not collapse.
// or, you can remove all expanded children keys.
this.setState({
expandedKeys,
autoExpandParent: false
});
};
onSelect = (selectedKeys, info) => {
console.log("onSelect", info);
this.setState({ selectedKeys });
};
renderTreeNodes = data =>
data.map(item => {
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{this.renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode key={item.key} {...item} />;
});
onExpandAll = () => {
const expandedKeys = [];
const expandMethod = arr => {
arr.forEach(data => {
expandedKeys.push(data.key);
if (data.children) {
expandMethod(data.children);
}
});
};
expandMethod(treeData);
this.setState({ expandedKeys });
};
onCollapseAll = () => {
this.setState({ expandedKeys: [] });
};
render() {
return (
<Fragment>
<Button onClick={this.onExpandAll} type="primary">
ExpandAll
</Button>
<Button onClick={this.onCollapseAll} type="primary">
CollapseAll
</Button>
<Tree
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
selectedKeys={this.state.selectedKeys}
>
{this.renderTreeNodes(treeData)}
</Tree>
</Fragment>
);
}
}
please refer to the Codesandbox link
I am using cdn for react
Actually I have two JSON FILE,
abc.json
[
{
"apiKey":"642176ece1e7445e99244cec26f4de1f"
}
]
reactjs.json
[
{
"642176ece1e7445e99244cec26f4de1f": {
"src": "image_1.jpg",
"id" : "1"
}
}
]
I actually want that first of all I get apiKey from the first json file and after with the help of it i like to get the value of src
1) How can I do this in React using axios?
2) Is that Possible that we can directly get the src from reactjs.json ? If yes then How?
What I tried, but it gives error..
class FetchDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [],
api:[]
};
//this.listImages = this.listImages.bind(this);
}
componentDidMount() {
axios.get('abc.json').then(res => {
console.log(res);
this.setState({ api: res.data });
});
axios.get('reactjs.json').then(res => {
console.log(res);
this.setState({ images: res.data });
});
}
render() {
return (
<div>
{this.state.api.map((api, index) => (
<Pictures key={index} apikeys={api.apiKey} />
))}
</div>
);
}
}
class Pictures extends React.Component {
render() {
return (
<h1>
alt={this.props.apikeys}
</h1>
{this.state.images.map((images, index) => (
<h1 key={index}> apikeys={images.+`{this.props.apikeys}`+.src} </h1>
//Error at this point
))}
);
}
}
ReactDOM.render(
<FetchDemo/>,
document.getElementById("root")
);
Using axios you are making a request. This means that your JSON would be served from a end point. If you really need to require the json file in this fashion try importing
import abc from './abc.json';
componentDidMount = () => {
this.setState({
json: abc
})
}
I have this json object which I have taken from the news API and want to print out the author of just one of the articles. I wanted to know how to do it within a react component which I have called 'author'.
Here is the json object: it's too long to include here but have the link for you to see.
It's accessible from https://newsapi.org/ and has a total of 20 articles.
I have this react component which I am trying to then print one of the article's authors:
import React, { Component } from 'react';
const APIurl = 'https://newsapi.org/v2/top-headlines?
country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';
class Author extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
fetch(APIurl)
.then(response => response.json())
.then(response => {
this.setState({
articles: response
})
})
}
render() {
return (
<h5 class="f6 ttu tracked black-80">
{this.state.articles.article[0].author}
</h5>
);
}
}
export default Author;
However, something must not be quite right because I get this error:
TypeError: Cannot read property 'articles' of undefined
21 | render() {
22 | return (
23 | <h5 class="f6 ttu tracked black-80">
> 24 | {this.state.articles.articles[0].author}
25 | </h5>
26 | );
27 | }
I'm not sure what I have done wrong. Also sorry for the poor formating of the json object.
I've now made some changes after seeing what has been suggested below so that my code looks like this:
import React, { Component } from 'react';
const APIurl = 'https://newsapi.org/v2/top-headlines? country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';
class Author extends Component {
constructor(props) {
super(props);
this.state = {
articles: []
};
}
componentDidMount() {
fetch(APIurl)
.then(response => response.json())
.then(response => {
this.setState({
articles: response
})
})
}
render() {
const { articles } = this.state;
return (
<h5 class="f6 ttu tracked black-80">
{articles.length>0 && articles.articles[1].author}
</h5>
);
}
}
export default Author;
However, it still doesn't print out anything in the author react component even though when I go to the chrome developer tools and see the state of the component it looks like this:
State
articles: {…}
articles: Array[20]
0: {…}
1: {…}
author: "Davide Stoppini"
description: "A Pisa, divertente pareggio con i russi, più avanti per quanto riguarda la condizione fisica. Passi in avanti rispetto al Sion: bene gli esterni offensivi, anche i due attaccanti confermano la confide…"
publishedAt: "2018-07-21T20:20:21Z"
source: {…}
title: "Inter, fuochi d'artificio con lo Zenit: è 3-3. In gol Icardi e Lautaro"
url: "https://www.gazzetta.it/Calcio/Serie-A/Inter/21-07-2018/inter-fuochi-d-artificio-lo-zenit-3-3-gol-icardi-lautaro-280799153444.shtml"
urlToImage:"https://images2.gazzettaobjects.it/methode_image/2018/07/21/Calcio/Foto%20Calcio%20-%20Trattate/1d50f03c94d965c2ca84bd3eec0137c9_169_xl.jpg
*Note: this is only showing the first second element of the articles array.
Basically, you have to declare articles as empty array initially as follows:
this.state = {
articles: []
};
And also need to modify your code inside render as follows:
{this.state.articles && (this.state.articles.article.length>0) &&
this.state.articles.article[0].author
}
Hope it will help you.
The problem you are having is because your code is not prepared to go through the lifecycle of React. Before you get the data in the componentDidMount phase there is a render phase, that is where the error is happening. In that render phase articles should be an empty array without data and then you need a check to avoid rendering any stuff if the array is empty. So to avoid to have that error in the render phase before the componentDidMount phase you need to set in state an empty array called articles, and in the render method to check if it is not empty, to render the value you want.
import React, { Component } from 'react';
const APIurl = 'https://newsapi.org/v2/top-headlines?
country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';
class Author extends Component {
constructor(props) {
super(props);
this.state = { articles: []};
}
componentDidMount() {
fetch(APIurl)
.then(response => response.json())
.then(response => {
this.setState({
articles: response.articles
})
})
}
render() {
const { articles } = this.state;
return (
<h5 class="f6 ttu tracked black-80">
{articles.length > 0 && articles[0].author}
</h5>
);
}
}
export default Author;
News App in React Native:
const SITE_URL =
"https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=a39bbc7131c649a3ad23fe79063d996f";
const TestScreen = () => {
const [myData, setMyData] = useState();
useEffect(() => {
axios
.get(SITE_URL)
.then((res) => {
// console.log("Response from main API: ", res);
console.log(
"----------------------------------------------------------- Start"
);
// console.log("Response from Home Data Data: ", res.data.data);
console.log(
"Response from NEWS data articles: ",
res.data.articles
);
console.log(
"----------------------------------------------------------- End"
);
// let companyData = res.data.data;
let companyData = res.data.articles;
setMyData(companyData);
setData({
Company: companyData,
Description: "",
});
})
.catch((err) => {
console.log(err);
});
}, []);
// console.log("myData:", { myData });
const renderItem = ({ item, index }) => (
<TouchableOpacity style={styles.container}>
<Text style={styles.title}>
{index}. {item.author}
</Text>
<Text> {item.description} </Text>
<View>
<Image
style={{
width: 500,
height: 100,
}}
source={{
uri: item.urlToImage,
}}
/>
</View>
</TouchableOpacity>
);
return (
<View style={styles.container}>
<Text>Read Later Screen</Text>
<Text>|</Text>
{<FlatList data={myData} renderItem={renderItem} />}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
export default TestScreen;
I would like to display InfoWindow on Marker click. I followed some tutorials and I used react-google-maps for my project. I would like my app to work like this: "https://tomchentw.github.io/react-google-maps/basics/pop-up-window" but my code is a little bit different.
class Map extends React.Component {
handleMarkerClick(){
console.log("Clicked");
}
handleMarkerClose(){
console.log("CLOSE");
}
render(){
const mapContainer= <div style={{height:'100%',width:'100%'}}></div>
//fetch markers
const markers = this.props.markers.map((marker,i) => {
return (
<Marker key={i} position={marker.location} showTime={false} time={marker.time} onClick={this.handleMarkerClick} >
{
<InfoWindow onCloseClick={this.handleMarkerClose}>
<div>{marker.time}</div>
</InfoWindow>
}
</Marker>
)
})
/* set center equals to last marker's position */
var centerPos;
if(markers[markers.length-1]!== undefined)
{
centerPos=markers[markers.length-1].props.position;
}
else {
centerPos={};
}
return (
<GoogleMapLoader
containerElement={mapContainer}
googleMapElement={
<GoogleMap
defaultZoom={17}
center={centerPos}
>
{markers}
</GoogleMap>
}/>
);
}
}
export default Map;
I got "this.props.markers" from another class component, which fetching data from URL. I am almost sure, that it is easy problem to solve. Currently on marker click in console I got "Clicked" and on Marker close "CLOSE" as you can guess from above code it is because of handleMarkerClick() and handleMarkerClose(). I want to have pop-window with InfoWindow.
What should I do to make it work?
Here is heroku link : App on heroku
Hi I came across the same requirement. I did this (I am using redux and redux-thunk) :
GoogleMap.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {
withGoogleMap,
GoogleMap,
Marker,
InfoWindow
} from 'react-google-maps';
import { onMarkerClose } from '../actions/Cabs';
const GettingStartedGoogleMap = withGoogleMap(props => (
<GoogleMap
defaultZoom={12}
defaultCenter={{ lat: 12.9716, lng: 77.5946 }}
>
{props.markers.map( (marker, index) => (
<Marker {...marker} onClick={() => props.onMarkerClose(marker.key)}>
{marker.showInfo &&(
<InfoWindow onCloseClick={() => props.onMarkerClose(marker.key)}>
<div>
<h1>Popover Window</h1>
</div>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
));
class CabType extends Component{
constructor(props){
super(props);
}
render(){
if(this.props.cabs.length === 0){
return <div>loading...</div>
}
return(
<div className="map-wrapper">
<GettingStartedGoogleMap
containerElement={
<div style={{ height: '100%' }} />
}
mapElement={
<div style={{ height: '100%' }} />
}
onMarkerClose = {this.props.onMarkerClose}
markers={this.props.showMap ? this.props.markers : []}
/>
</div>
)
}
}
export default connect(store => {return {
cabs : store.cabs,
markers: store.markers
}}, {
onMarkerClose
})(CabType);
Action.js
const getMarkers = (cabs , name) => dispatch => {
let markers = [];
let data = {};
cabs.map(cab => {
if(cab.showMap){
data = {
position: {
lat : cab.currentPosition.latitude,
lng : cab.currentPosition.longitude
},
showInfo: false,
key: cab.cabName,
icon: "/images/car-top.png",
driver: cab.driver,
contact: cab.driverContact,
};
markers.push(data);
}
});
dispatch(emitMarker(markers));
};
function emitSetMarker(payload){
return{
type: SET_MARKER,
payload
}
}
export const onMarkerClose = (key) => dispatch => {
dispatch(emitSetMarker(key))
};
RootReducer.js
import { combineReducers } from 'redux';
import { cabs } from "./Cabs";
import { markers } from "./Markers";
const rootReducer = combineReducers({
cabs,
markers,
});
export default rootReducer;
MarkerReducer.js
import { GET_MARKERS, SET_MARKER } from "../types"
export const markers = (state = [], action) => {
switch (action.type){
case GET_MARKERS:
return action.payload;
case SET_MARKER:
let newMarker = state.map(m => {
if(m.key === action.payload){
m.showInfo = !m.showInfo;
}
return m;
});
return newMarker;
default: return state;
}
};
Sorry for a long post but this is code which is tested and running. Cheers!