googlemapapiI'm having issues fetching google map, it says the page can't load correctly, I also have some errors on my console. I don't understand what I'm doing wrong, I should be able to make a query and have the places showing in the suggestions, but I'm doing something wrong. here is my component, I have also attached a photo. All help will be welcome [
import React, { Component } from "react";
import { Map, Marker, GoogleApiWrapper } from "google-maps-react";
const apiKey = process.env.REACT_APP_GOOGLE_API_KEY;
const center = {
lat: 51.5074,
lng: 0.1278,
};
let service = null;
export class MapContainer extends Component {
constructor(props) {
super(props);
this.state = {
input: "",
suggestions: [],
places: [],
};
}
savePlace = (place) => {
this.setState({ places: [...this.state.places, place] });
};
handleChange = (e) => {
this.setState({ input: e.target.value });
};
handleKeyPress = (event) => {
if (event.key === "Enter") {
this.search();
}
};
search = () => {
const {input} = this.state;
service.textSearch({query: input}, (suggestions) => {
this.setState({suggestions});
})
};
initPlaces(mapProps, map) {
const { google } = mapProps;
service = new google.maps.places.PlacesService(map);
}
render() {
const { suggestions, places } = this.state;
return (
<div className="container">
<div className="row">
<div className="col">
<div className="form-inline d-flex justify-content-between mb-4">
<input
type="text"
value={this.state.input}
onChange={this.handleChange}
className="form-control flex-grow-1"
placeholder="Search for places on Google Maps"
onKeyPress={this.handleKeyPress}
/>
<button onClick={this.search} className="btn btn-primary ml-2">
Search
</button>
</div>
<h3>Suggestions</h3>
<ul className="list-group">
{suggestions.map((place, i) => (
<li
key={i}
className="list-group-item d-flex justify-content-between align-items-center"
>
<div>
<div>
<strong>{place.name}</strong>
</div>
<span className="text-muted">
{place.formatted_address}
</span>
</div>
<button
className="btn btn-outline-primary"
onClick={() => this.savePlace(place)}
>
Show
</button>
</li>
))}
</ul>
</div>
<div className="col">
<Map google={this.props.google} zoom={14} initialCenter={center} onReady={this.initPlaces}></Map>
</div>
</div>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey,
})(MapContainer);
]2
I checked your code and if you directly put your API key in your
const apiKey = "PUT_YOUR_API_KEY_HERE"; , it will properly show your map.
It seems that you are putting your variables in the .env file (refer here on how to add custom environment variables). Make sure that you put your .env file outside the src folder and set this inside your .env file :
REACT_APP_GOOGLE_API_KEY=API_KEY_VALUE_HERE. This works for me.
You can find the sample code in this link.
Make sure to change the value of the REACT_APP_GOOGLE_API_KEY in the .env file to your API key.
Hope this helps!
Related
What I am Trying to do is to fetch data from a Weather API on button click and when the data is fetched then that data should be mapped inside a component(i.e. Weather) and then only that component should appear on the screen, right now I am able to fetch the data but even then the component is not appearing.
Container.jsx
import React from 'react';
import './container.css'
import Weather from './weather';
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
location: "",
weather: []
};
}
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
componentDidMount() {
}
continue = (e) => {
const { location } = this.state;
const rawurl = 'http://api.weatherstack.com/current?access_key=d8fefab56305f5a343b0eab4f837fec1&query=' + location;
const url = rawurl;
//e.preventDefault();
if (location.length < 1) {
return alert('Enter the details');
}
else {
fetch(url)
.then(response => response.json())
.then(data =>{
this.setState({weather:data});
})
.catch(err => console.log("error ",err))
}
};
render() {
console.log(this.state);
const weather =
this.state.weather.length> 0 ?
this.state.weather.map(item => (<Weather location={item.location.name} temperature={item.current.temperature} weather={item.current.weather_descriptions[0]} windSpeed={item.current.wind_speed} windDegree={item.current.wind_degree} windDir={item.current.wind_dir} humidity={item.current.humidity} visibility={item.current.visibility} />
))
:<span></span>
return (
<div id="container">
<div class="searchicon">
<input type="search" placeholder="Enter City !!" type="text" name="location" value={this.state.location} onChange={this.handleChange}></input>
<label class="icon">
<button onClick={this.continue}><span class="fa fa-search"></span></button>
</label>
</div>
<div>
{weather}
</div>
</div>
);
}
}
export default Container;
Weather.jsx
import React from 'react';
class Weather extends React.Component {
render(){
return (
<div id="result">
<div id="location" class="insideres">
<div class="title">
Location
</div>
<div class="res">
{this.props.location}
</div>
</div>
<div id="Temperature" class="insideres">
<div class="title">
Temperature
</div>
<div class="res">
{this.props.temperature}
</div>
</div>
<div id="Weather" class="insideres">
<div class="title">
Weather
</div>
<div class="res">
{this.props.weather}
</div>
</div>
<div id="Windspeed" class="insideres">
<div class="title">
Wind Speed
</div>
<div class="res">
{this.props.windSpeed}
</div>
</div>
<div id="Wind_degree" class="insideres">
<div class="title">
Wind Degree
</div>
<div class="res">
{this.props.windDegree}
</div>
</div>
<div id="Wind_dir" class="insideres">
<div class="title">
Wind Direction
</div>
<div class="res">
{this.props.windDir}
</div>
</div>
<div id="Humidity" class="insideres">
<div class="title">
Humidity
</div>
<div class="res">
{this.props.humidity}
</div>
</div>
<div id="Visibility" class="insideres">
<div class="title">
Visibility
</div>
<div class="res">
{this.props.visibility}
</div>
</div>
</div>
);
}
}
export default Weather;
I want this weather component to appear when the data is fetched from the api, but right now data is being fetched but its not appearing.
In the above image you can see I am getting data from api, but not getting Weather component with that data under searchbar
Here is an update to your component using react with hooks. I highly suggest you adopt this pattern as it is way easier to work with, but does require using React 16 if you haven't adopted this yet. You will notice that I:
am using template strings instead of concatenating strings. This is best practice.
use async/await with promises
using an if statement to render the Weather component if the length of the weather variable in state is greater than 0. If it isn't, it will render the container component.
import "./container.css";
import React, { useState } from "react";
import Weather from "./weather";
const Container = () => {
const [location, setLocation] = useState("");
const [weather, setWeather] = useState([]);
const fetchWeatherData = async () => {
const url = `http://api.weatherstack.com/current?access_key=d8fefab56305f5a343b0eab4f837fec1&query=${location}`;
if (location.length < 1) {
return alert("Enter the details");
} else {
await fetch(url)
.then((response) => response.json())
.then((data) => {
setWeather(data);
})
.catch((err) => console.log("error ", err));
}
};
if (weather.length > 0) {
return weather.map((item) => (
<Weather
location={item.location.name}
temperature={item.current.temperature}
weather={item.current.weather_descriptions[0]}
windSpeed={item.current.wind_speed}
windDegree={item.current.wind_degree}
windDir={item.current.wind_dir}
humidity={item.current.humidity}
visibility={item.current.visibility}
/>
));
}
return (
<div id="container">
<div className="searchicon">
<input
placeholder="Enter City !!"
type="text"
name="location"
value={location}
onChange={(e) => setLocation(e.target.value)}
/>
<label className="icon">
<button onClick={fetchWeatherData}>
<span className="fa fa-search" />
</button>
</label>
</div>
<div>{weather}</div>
</div>
);
};
export default Container;
I have created a ToDo App in React. I want to add a single button which when I clicked on removes the whole todo list and shows the message to the user "You don't have any todo's". I am trying to add functionality but can't seem to find a perfect way.
I have given all the Todos a unique id and I also to grab these id's but don't how to use them to remove all Todos from a single button only. Help me. Thanks in advance
here is my main component App.js
import React, { Component } from 'react';
import PrintTodo from "./printtodo"
import Addtodo from "./addTodo"
class App extends Component {
state = {
todos: [
{id:1, content:"Buy Tomatoes"},
]
}
deleteTodo = (id) => {
const todos = this.state.todos.filter(todo => {
return todo.id !== id
})
this.setState({
todos
})
}
addTodo = (todo) => {
todo.id = Math.random()
// console.log(todo)
let todos = [...this.state.todos, todo]
this.setState({
todos
})
}
button = () => {
// console.log(this.state)
const allTodos = this.state.todos.filter(todo => {
console.log(todo)
})
// const id = 10;
// console.log(allTodos)
// allTodos.forEach(todo => {
// // console.log(todo)
// const arr = new Array(todo)
// arr.pop()
// })
}
render(){
// console.log(this.state)
return (
<div className="App">
<div className="container">
<header className="text-center text-light my-4">
<h1>ToDo - List</h1>
<form>
<input type="text" name="search" placeholder="Search ToDo's" className="form-control m-auto"/>
</form>
</header>
<PrintTodo addTodo={this.state.todos} deleteTodo={this.deleteTodo}/>
<Addtodo addTodo={this.addTodo} allTodos={this.button}/>
</div>
</div>
)
}
}
export default App;
PrintTodo Component
import React from 'react'
const printTodo = ({addTodo, deleteTodo, }) => {
// console.log(addTodo)
const todoList = addTodo.length ? (
addTodo.map(todo => {
return (
<ul className="list-group todos mx-auto text-light" key={todo.id}>
<li className="list-group-item d-flex justify-content-between align-items-center">
<span>{todo.content}</span>
<i className="far fa-trash-alt delete" onClick={()=>{deleteTodo(todo.id)}}></i>
</li>
</ul>
)
})
) : (
<p className="text-center text-light">You don't have any ToDo's</p>
)
return (
<div>
{todoList}
</div>
)
}
export default printTodo
AddTodo Component
import React, { Component } from 'react'
class Addtodo extends Component{
state = {
content: ""
}
handleChange = (e) => {
this.setState({
content: e.target.value
})
}
handleSubmit = (e) => {
e.preventDefault()
this.props.addTodo(this.state)
this.setState({
content: ""
})
}
render(){
// console.log(this.props.allTodos)
return(
<div>
<form className="text-center my-4 add text-light" onSubmit={this.handleSubmit}>
<label htmlFor="add">Add a New ToDo</label>
<input onChange={this.handleChange} type="text" name="add" id="add" className="form-control m-auto" value={this.state.content}/>
</form>
<button onClick={() => {this.props.allTodos()}}>Clear Whole List</button>
</div>
)
}
}
export default Addtodo
In your app.js make this your button component.
button = () => {
this.setState({todos: []})
})
Resetting your todos to an empty array will delete all your todos.
I have a react app that I made in VS Studio, putting it into codepen, it doesnt seem to load a thing, any suggestions?
I have tried making sure React is linked and checked all of my syntax, no errors on local host but no display in codepen.
I have looked through the code multiple times and I feel its such a silly mistake
https://codepen.io/donnieberry97/pen/EzmOvW
class TodoListt extends React.Component {
state = {};
constructor(props) {
super(props);
this.state = {
userInput: "",
list: [],
editing: false,
};
}
changeUserInput(input) {
this.setState({
userInput: input
})
}
addToList() {
if (this.state.userInput === "") { (alert("Please enter a To-do")); return; };
const { list, userInput } = this.state;
this.setState({
list: [...list, {
text: userInput, key: Date.now(), done: false
}],
userInput: ''
})
}
handleChecked(e, index) {
console.log(e.target.checked);
const list = [...this.state.list];
list[index] = { ...list[index] };
list[index].done = e.target.checked;
this.setState({
list
})
}
handleEditing(e) {
this.setState({
editing: true
})
}
handleRemoved(index) {
const list = [...this.state.list];
list.splice(index, 1);
this.setState({
list
})
}
render() {
var viewStyle = {};
var editStyle = {};
if (this.state.editing) {
viewStyle.display = "none"
}
else {
editStyle.display = "none"
}
return (
<div className="to-do-list-main">
<input
onChange={(e) => this.changeUserInput(e.target.value)}
value={this.state.userInput}
type="text"
/>
<div class="submitButton">
<button onClick={() => { this.addToList(this.state.userInput) }}>Add todo</button>
</div>
{this.state.list.map((list, index) => (
<div className="form">
<ul>
{/* <div style={viewStyle} onDoubleClick={this.handleEditing.bind(t his)}> */}
<li key={list.key}>
<div class="liFlexCheck">
<input type="checkbox" onChange={(e) => this.handleChecked(e, index)} />
</div>
<div class="liFlexText">
<div class="liFlexTextContainer">
<span style={{ textDecoration: list.done ? 'line-through' : 'inherit' }}>
{list.text}
</span>
</div>
</div>
<button onClick={(index) => this.handleRemoved(index)}>Remove</button>
<input
type="text"
style={editStyle}
value={list.text}
/>
</li>
{/* </div> */}
</ul>
</div>
))}
</div>
);
}
}
Remove the import statements, working example.
You shouldn't use import when you got External Scripts.
Also, you got many errors in your code that should be handled, like:
<div class="submitButton">, use className.
Each child in a list should have a unique key prop.
Form field with value prop but without onChange handler.
Check out the logs:
In codpen, you don't need to import the react instead just write code,
here is codepen working one : codepen
from codesandbox, you can learn with all imports also because it doesn't uses any external scripts,
your code will work fine if you add an import to it
that is import ReactDOM from 'react-dom';
codesandbox will show all these suggestions,
here is codesandbox working example: codesandbox
I was working on a forum project,Ii used firestore as backend database, react, and redux.
I have an issue whenever someone post a comment on new post with no comment, it does not show, but after refresh is appears, all comments after that appears normally.
github https://github.com/nikhilb2/Forum
deployment http://mariosforum.surge.sh/signin
Can anyone please help me.
import React, { Component } from "react";
import { postComment } from "../../store/actions/projectActions";
import { connect } from "react-redux";
import moment from "moment";
class Comment extends Component {
constructor(props) {
super(props);
this.state = {
comment: "",
authorId: "",
projectId: ""
};
this.handleContent = this.handleContent.bind(this);
this.handlePost = this.handlePost.bind(this);
}
handleContent(e) {
this.setState({
comment: e.target.value,
projectId: this.props.projectId,
authorId: this.props.auth.uid
});
}
handlePost() {
this.props.postComment(this.state);
this.refs.comment.value = "";
}
render() {
const { user, project, state } = this.props;
console.log(`user`);
console.log(this.props);
return user ? (
<div className="container">
{project &&
project.comment &&
Array.isArray(project.comment) &&
project.comment.map(comment => {
const authorId = comment.authorId;
//console.log(user[authorId]);
//console.log(authorId)
return (
<div className="container project-details">
<div className="card z-depth-0">
<div className="card-content">
{comment.comment}
<div className="card-action grey lighten-4 grey-text">
{user[authorId] ? user[authorId].firstName : authorId}{" "}
{user[authorId] ? user[authorId].lastName : authorId}
<div>
{comment.time
? moment(comment.time.toDate()).calendar()
: authorId}
</div>
</div>
</div>
</div>
</div>
);
})}
<div className="card z-depth-0">
<div className="card-content">
<div className="input-field">
<label htmlFor="comment">Type Comment</label>
<textarea
id="comment"
ref="comment"
type="text"
className="materialize-textarea"
onChange={this.handleContent}
/>
</div>
<button
className="btn pink lighten-1 z-depth-0"
onClick={this.handlePost}
>
Post
</button>
</div>
</div>
</div>
) : null;
}
}
const mapDispatchToProps = dispatch => {
return {
postComment: project => dispatch(postComment(project))
};
};
const mapStateToProps = state => {
console.log(state);
return {
state: state
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Comment);
It sounds similar to a problem I had with the same setup. Adding following line to the react-redux-firebase settings in your index.js file might solve the problem:
allowMultipleListeners: true
export const postComment = (project) => {
return(dispatch,getState,{getFirestore}) =>{
const firestore = getFirestore()
console.log(getState())
firestore.collection('projects').doc(project.projectId).update({
comment: firestore.FieldValue.arrayUnion({
comment:project.comment,
authorId:project.authorId,
time: new Date()})
}).then(()=>{
dispatch({
type:'POST_COMMENT',
project
})
}).catch((err)=>{
dispatch({type:'POST_COMMENT_ERROR'})
})
}}
You need to add an action to update redux store for comments, so every time you make a comment it will update redux store
I am trying to make a modal component which I can reuse, but I don't get what I am doing wrong here. The Modal is not appearing. Can anyone help me out?
Little explanation about my app.
This app is loading a JSON url and shows a list of products, which can be marked as done. If you click the div plaatjediv you should get a popup (the modal) with details info over the clicked product.
EDIT: Edited the code as suggested here. I can see the state change to true and false if I click the div, but the Modal is still not appearing.
my code
App.js
import React from 'react';
import ProductModal from './ProductModal.js';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleModal = this.toggleModal.bind(this);
this.state = {
isLoading: true,
orders: [],
dealtOrders: [],
open: false
}
}
toggleModal() {
this.setState({
open: !this.state.open
});
}
componentWillMount() {
localStorage.getItem('orders') && this.setState({
orders: JSON.parse(localStorage.getItem('orders')),
isLoading: false
})
}
componentDidMount() {
if (!localStorage.getItem('orders')){
this.fetchData();
} else {
console.log('Using data from localstorage');
}
}
fetchData() {
fetch('http://localhost:54408/api/orders/all/26-03-2018')
.then(response => response.json())
.then(parsedJSON => parsedJSON.map(product => (
{
productname: `${product.ProductName}`,
image: `${product.Image}`,
quantity: `${product.Quantity}`,
isconfirmed: `${product.IsConfirmed}`,
orderid: `${product.OrderId}`
}
)))
.then(orders => this.setState({
orders,
isLoading: false
}))
.catch(error => console.log('parsing failed', error))
}
render() {
this.handleDoneAction = event =>
{
let itemIndex = event.target.getAttribute("data-itemIndex");
let prevOrders = [...this.state.orders];
let dealtOrders = [...this.state.dealtOrders];
const itemToMoveAtLast = prevOrders.splice(itemIndex, 1);
const addToDealtOrders = dealtOrders.concat(itemToMoveAtLast);
this.setState({dealtOrders: addToDealtOrders});
this.setState({orders: prevOrders});
};
this.handleUndoAction = event =>
{
let itemIndex = event.target.getAttribute("data-itemIndex");
let orders = [...this.state.orders];
let dealtOrders = [...this.state.dealtOrders];
const undoDealtOrder = dealtOrders.splice(itemIndex, 1);
const addToOrders = orders.concat(undoDealtOrder);
this.setState({orders: addToOrders});
this.setState({dealtOrders: dealtOrders});
};
const {isLoading, orders, dealtOrders,open} = this.state;
return (
<div>
<header>
<img src="/images/header.jpg"/>
<h1>Boodschappenlijstje <button className="btn btn-sm btn-danger">Reload</button></h1>
</header>
<ProductModal open={open} />
<div className={`content ${isLoading ? 'is-loading' : ''}`}>
<div className="panel">
{
!isLoading && orders.length > 0 ? orders.map((order, index) => {
const {productname, image, quantity, orderid} = order;
return<div className="product" key={orderid}>
<div className="plaatjediv" onClick={this.toggleModal}>
<img className="img-responsive" src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
</div>
<div className="bdone">
<button className="btn btn-lg btn-default btndone" data-itemIndex={index} onClick={this.handleDoneAction}>Done</button>
</div>
</div>
}) : null
}
</div>
<h2>Mandje</h2>
<div className="panel">
{
!isLoading && dealtOrders.length > 0 ? dealtOrders.map((dorder, index) => {
const {productname, image, quantity, orderid} = dorder;
return<div className="productDone" key={index}>
<div className="plaatjediv">
<img className="img-responsive" src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
</div>
<div className="bdone">
<button className="btn btn-lg btn-default btndone" data-itemIndex={index} onClick={this.handleUndoAction}>Undo</button>
</div>
</div>
}) : null
}
</div>
<div className="loader">
<div className="icon"></div>
</div>
</div>
</div>
);
}
} export default App;
ProductModal.js
import React from 'react';
class ProductModal extends React.Component {
constructor() {
super();
}
render() {
const open = this.props.open;
return (
<div className={'modal fade'+(open ? '' : 'hide')} tabindex="-1" role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 className="modal-title">test</h4>
</div>
<div className="modal-body">
test
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" className="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
)
}
}
export default ProductModal;
I am unsure what your issue is from your question but I am guessing your model doesn't open?
When you set state, you need to set it to the opposite of this.state.open
You can do it like this:
toggleModal() {
this.setState({
open: !this.state.open
});
}
I can't see where the modal is supposed to be rendered. You have to add it to render function of your "App" class. like this:
render() {
...
return(
<ProductModal open={true} />
...
):
}
and also, in your toggleModal function, do something like this:
this.setState({ open: !this.state.open});
Hope this solves the issue.
The issue is that you do not have your <ProductModal /> as a component in your <App /> In addition to setting your open state, once shown, it will (or should) never hide because you will not be able to toggle it again using your button, and you also do not have any keybindings within your <ProductModal /> itself.
I would suggest you bind an event listener within <ProductModal /> to
Check is ESC key is pressed
Bind a Cancel/Close button (in addition to a header x button).
Listen for if anywhere outside of your dialog is clicked, dismiss the modal.
You will also need to pass a handler from <App /> down to <ProductModal /> to notify when the modal has been closed.
In your App.js
handleClose() {
this.setState({
open: false
});
}
render() {
return (
...
<ProductModal open={this.state.open} handleClose={this.handleClose.bind(this)} />
)
}
Then in your ProductModal.js
handleClose() {
this.props.handleClose();
}
Observe the following using my sandbox:
https://stackblitz.com/edit/react-98m4cr
You'll see that I've implemented the handleClose event to control the state back up to the parent. In addition, you may want to add listeners as mentioned above, all triggering handleClose in the end; just remember to unbind them in ProductModal.js componentWillUnmount.