React: Export function to use in another component - reactjs

I'm building out a Google Map on my Gatsby site with a search box that will allow users to search for their location. I've got a Hero component and a Map component, and all of the functionality is built into the Map component; the Google Maps API, autocomplete, Google Places etc. Here's what it looks like right now:
Map.tsx
import React, { useState, useRef, useCallback } from 'react';
import { GoogleMap, useLoadScript, Marker, InfoWindow } from '#react-google-maps/api';
import * as dealersData from 'assets/data/dealers.json';
import { Button } from 'components/button/Button';
import MapMarker from 'assets/images/icons/map-marker.png';
import SearchIcon from 'assets/svg/search.svg';
import usePlacesAutocomplete, { getGeocode, getLatLng } from 'use-places-autocomplete';
import {
Combobox,
ComboboxInput,
ComboboxPopover,
ComboboxList,
ComboboxOption,
} from '#reach/combobox';
import '#reach/combobox/styles.css';
import s from './Map.scss';
import MapStyles from './_MapStyles';
const libraries = ['places'];
const mapContainerStyle = {
width: '100%',
height: '100%',
};
const options = {
styles: MapStyles,
disableDefaultUI: true,
zoomControl: true,
};
interface MapProps {
location: any;
fetchedData: ReactNode;
}
export const Map = ({ location, fetchedData }: MapProps) => {
const center = {
lat: location.location.latitude,
lng: location.location.longitude,
};
const [selectedDealer, setselectedDealer] = useState(null);
const { isLoaded, loadError } = useLoadScript({
googleMapsApiKey: process.env.GATSBY_GOOGLE_MAPS_API,
libraries,
});
const mapRef = useRef();
const onMapLoad = useCallback((map) => {
mapRef.current = map;
}, []);
const panTo = useCallback(({ lat, lng }) => {
mapRef.current.panTo({ lat, lng });
mapRef.current.setZoom(10);
}, []);
if (loadError) return <div className={s.map}>Error loading maps...</div>;
if (!isLoaded) return <div className={s.map}>Loading...</div>;
return (
<>
<div className={s.map}>
<div className={s.map__search}>
<Search panTo={panTo}></Search>
</div>
<GoogleMap
mapContainerStyle={mapContainerStyle}
zoom={10}
center={center}
options={options}
onLoad={onMapLoad}
>
{dealersData.features.map((dealer) => (
<Marker
key={dealer.properties.DEALER_ID}
position={{
lat: dealer.geometry.coordinates[1],
lng: dealer.geometry.coordinates[0],
}}
onClick={() => {
setselectedDealer(dealer);
}}
icon={{
url: MapMarker,
scaledSize: new window.google.maps.Size(30, 30),
}}
/>
))}
{selectedDealer && (
<InfoWindow
position={{
lat: selectedDealer.geometry.coordinates[1],
lng: selectedDealer.geometry.coordinates[0],
}}
onCloseClick={() => {
setselectedDealer(null);
}}
>
<div className={s.dealer}>
<h2 className={s.dealer__name}>
{selectedDealer.properties.NAME}
<span className={s.phone}>{selectedDealer.properties.PHONE_NUMBER}</span>
</h2>
<div className={s.dealer__info}>
<p className={s.address}>{selectedDealer.properties.ADDRESS}</p>
<p className={s.address}>
{selectedDealer.properties.CITY}, {selectedDealer.properties.STATE}{' '}
{selectedDealer.properties.ZIP_CODE}
</p>
</div>
<Button>Set Location</Button>
</div>
</InfoWindow>
)}
</GoogleMap>
</div>
</>
);
};
export function Search({ panTo }) {
const {
ready,
value,
suggestions: { status, data },
setValue,
clearSuggestions,
} = usePlacesAutocomplete({
requestOptions: {
location: { lat: () => 38.8299359, lng: () => -121.3070356 },
radius: 200 * 1000,
},
});
return (
<>
<div className={s.search__input}>
<i className={s.search__icon}>
<SearchIcon />
</i>
<Combobox
onSelect={async (address) => {
setValue(address, false);
clearSuggestions();
try {
const results = await getGeocode({ address });
const { lat, lng } = await getLatLng(results[0]);
panTo({ lat, lng });
} catch (error) {
console.log('error');
}
}}
>
<ComboboxInput
value={value}
onChange={(e: any) => {
setValue(e.target.value);
}}
disabled={!ready}
placeholder="Enter your location"
/>
<ComboboxPopover>
<ComboboxList>
{status === 'OK' &&
data.map(({ id, description }) => <ComboboxOption key={id} value={description} />)}
</ComboboxList>
</ComboboxPopover>
</Combobox>
</div>
</>
);
}
And here's my Hero component:
Hero.tsx
import React from 'react';
import s from './Hero.scss';
import { RichText } from 'prismic-reactjs';
import { linkResolver } from 'utils/linkResolver';
import htmlSerializer from 'utils/htmlSerializer';
import { Search } from '../map/_Map';
export const Hero = ({ content, panTo }: any) => (
<div className={s.hero} data-theme={content.theme}>
<div className={s.hero__container}>
<div className={s.content}>
<h1 className={s.content__heading}>{RichText.asText(content.page_title)}</h1>
<div className={s.content__copy}>
{RichText.render(content.copy, linkResolver, htmlSerializer)}
</div>
<Search panTo={panTo}></Search>
</div>
</div>
</div>
);
Essentially, I'm needing to utilize the Search function in my Hero component, but when I export it and import it into the Hero its rendering just fine, but it never loads the use-places-autocomplete library, and won't work. What am I doing wrong? Is there any way to export the search function to reuse?
I've created an SSCCE, as asked in the comments here. The search function works if I utilize it directly in the Map component, but if it's imported into the hero, it doesn't load.
https://codesandbox.io/s/dawn-glitter-zi7lx
Thanks.

Thanks for providing the sscce of your code in codesandbox. It looks like you are loading the Google Maps Javascript script tag only inside the <Map/> and not inside <Hero/>. You can see in your console log that there is a message to load the library.
To make it work, I used LoadScript of #react-google-maps/api in your index.tsx and put both and components in order for both script to work. Here's a sample of the index.tsx.
import React from "react";
import ReactDOM from "react-dom";
import { LoadScript } from "#react-google-maps/api";
import { Map } from "./Map";
import { Hero } from "./Hero";
const rootElement = document.getElementById("root");
const App = () => {
return (
<React.StrictMode>
<LoadScript
googleMapsApiKey="YOUR_API_KEY"
libraries={["places"]}
>
<Hero />
<Map />
</LoadScript>
</React.StrictMode>
);
};
ReactDOM.render(<App />, rootElement);
I also removed useLoadScript in Map.tsx to make sure that it won't have conflict with the script loaded in the index.tsx.

Related

Why the context variable failed to pass from componet Header.jsx to mainPage.js

I would like the wording used for the layout inside mainPage would change according to the language selected at component Header.jsx. However, change in Header.jsx could not pass to Header.jsx, therefore, noting is changed when clicking on the language selector.
import React, { useState, useEffect } from "react";
import Header from "../Resources/Components/Header";
import Footer from "../Resources/Components/Footer";
import {MainPageContext, useMainPageContext } from "../Resources/Hooks/mainPageContext";
import "./MainPage.css";
const MainPage = () => {
const context = useMainPageContext();
const {
language,
} = context;
useEffect(()=>{
console.log("is me hi!")
},[language])
const [introductionPage, setIntroductionPage] = useState(0);
console.log("language is", language)
//const [language, setLanguage]= useState(0);
//below is the script of the test description. 隨時可以加入新array做新language。
const renderLanguageSwitch= (language) => {
switch(language) {
case 0:
return ['測試開始','測試資料採集同意書'];
case 1:
return ['Test Start', 'Test Data Collection Agreement']
default:
return ['測試開始','測試資料採集同意書'];
}
};
const renderButtonSwitch= (language) => {
switch(language) {
case 0:
return ['我同意', '我拒絕'];
case 1:
return ['I agree', 'I disagree']
default:
return ['我同意', '我拒絕'];
}
};
return (
<div className="MainPage">
<Header />
<div
style={{
width: "100%",
height: "100vh",
backgroundColor: "#F5821F",
margin: "0",
}}
>
{introductionPage === 0 && (
<button
className="testStartBox"
onClick={() => {
setIntroductionPage(1);
}}
>
{renderLanguageSwitch(language)[0]}
</button>
)}
{introductionPage !== 0 && (
<div>
<div
className="testDescriptionBox"
onClick={() => {
setIntroductionPage(introductionPage + 1);
}}
>
{renderLanguageSwitch(language)[1]}
</div>
<div className="testAgreement">
</div>
</div>
)}
<div
className="buttonWrapper"
style={{ display: introductionPage === 1 ? "" : "none" }}
>
<button onClick={() => {
setIntroductionPage(introductionPage + 1);
}}> {renderButtonSwitch(language)[0]}</button>
<button onClick={() => {
setIntroductionPage(0);
}}>{renderButtonSwitch(language)[1]}</button>
</div>
</div>{" "}
<Footer />
</div>
);
};
export default MainPage;
There is a language selector on the component Header.jsx, I would like to change the language, then change the content of MainPage. However, it doesn't work.
import React from "react";
import { useMainPageContext } from "../Hooks/mainPageContext";
const Header = () => {
const context = useMainPageContext();
const {
language,
onSetLanguage,
} = context;
return (
<div className="header">
<h1
style={{
display: "flex",
flexFlow:"row",
alignItems:"center",
width: "calc(100% - 10%)",
height: "4vh",
}}
>
<div style={{display:"flex", color: "#F5821F",}}>
<img src={require("../Images/Logo.png")} style={{width:"50%", height:"7.5%", marginTop:"0vh"}} alt="image name"/>
<div style={{ top: "0", margin: "0vh", marginLeft:"2vw", width:" 100%", fontSize:"3vw"}}>中心</div>
</div>
<div><div style={{marginTop:"1vh", fontSize:"2vw"}} onClick={()=>{language===1? onSetLanguage(0):onSetLanguage(1);
}}>繁體/ English</div></div>
</h1>
</div>
);
};
export default Header;
I have changed the coding , so that it is a context variable passed to the mainPage.js, however, I have another problem, the missing transition key.
Here is my i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n
.use(initReactI18next)
.init({
backend: {
loadPath: `/locales/{{lng}}/translation.json`,
parse: data => data,
},
lng: 'en',
fallbackLng: 'en',
debug: true,
resources: {
'en': {
translation: 'en',
},
'tw': {
translation: 'tw',
},
},
interpolation: {
escapeValue: false
}
});
export default i18n;
Here is the App.js
import React , { Component, Suspense , useState, useCallback} from 'react';
import { useTranslation, withTranslation, Trans ,I18nextProvider} from 'react-i18next';
import ReactDOM from "react-dom/client";
import{
createBrowserRouter, RouterProvider,BrowserRouter as Router
} from "react-router-dom";
import logo from './logo.svg';
import './App.css';
//Import the pages
import MainPage from "./MainPage/MainPage";
import A1SubjectPage1 from "./ASubject/A1SubjectPage1";
import B1ResearcherPage1 from "./BResearcher/B1ResearcherPage1";
import Header from './Resources/Components/Header';
// use hoc for class based components
class LegacyWelcomeClass extends Component {
render() {
const { t } = this.props;
return <h2>{t('title')}</h2>;
}
}
const Welcome = withTranslation()(LegacyWelcomeClass);
// Component using the Trans component
/*function MyComponent() {
return (
<Trans i18nKey="description.part1">
To get started, edit <code>src/App.js</code> and save to reload.
</Trans>
);
}
*/
// page uses the hook
function App() {
const { t, i18n } = useTranslation();
const [language, setLanguage] = useState('en');
const onSetLanguage = useCallback((lng) => {
setLanguage(lng);
}, []);
const router = createBrowserRouter([
{
path: "/",
element: <div><MainPage/></div>,
},
{
path: "/mainPage",
element: <div>wowkdjfkdow<MainPage /></div>,
},
{
path: "/A1SubjectPage1",
element: <div>puripuri<A1SubjectPage1 /></div>,
},
{
path: "/B1ResearcherPage1",
element: <div>ReRe<B1ResearcherPage1 /></div>,
},
]);
ReactDOM.createRoot(document.getElementById("root")).render(
<I18nextProvider i18n={i18n}>
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
</I18nextProvider>
);
let routes;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> This is a project
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Hello World Again and Again
</a>
</header>
<Router>
<div className="App-intro">
</div>
<main>{routes}</main>
</Router>
</div>
);
}
export default App;
Here is the mainPage.js
import React, { useState, useEffect, Component , Suspense, useCallback} from "react";
import Header from "../Resources/Components/Header";
import Footer from "../Resources/Components/Footer";
import { useTranslation, withTranslation, Trans } from 'react-i18next';
import {MainPageContext, useMainPageContext } from "../Resources/Hooks/mainPageContext";
import "./MainPage.css";
class LegacyWelcomeClass extends Component {
render() {
const { t } = this.props;
return <h2>{t('title')}</h2>;
}
}
const Welcome = withTranslation()(LegacyWelcomeClass);
const MainPage = () => {
const { t, i18n } = useTranslation();
const context = useMainPageContext();
const [language, setLanguage] = useState('tw');
const onSetLanguage = useCallback((lng) => {
setLanguage(lng);
}, []);
const [introductionPage, setIntroductionPage] = useState(0);
//const [language, setLanguage]= useState(0);
//below is the script of the test description. 隨時可以加入新array做新language。
const renderLanguageSwitch = () => {
return [t('testStart'), t('testAgreement')];
};
const renderButtonSwitch = () => {
return [t('agree'), t('disagree')];
};
return (
<div className="MainPage">
<Trans i18nKey="title">
<h2>{t('title')}</h2>
</Trans>
<Header onSetLanguage={onSetLanguage} />
<div
style={{
width: "100%",
height: "100vh",
backgroundColor: "#F5821F",
margin: "0",
}}
>
{introductionPage === 0 && (
<button
className="testStartBox"
onClick={() => {
setIntroductionPage(1);
}}
>
{t('agree')}, {t('disagree')}
</button>
)}
{introductionPage !== 0 && (
<div>
<div
className="testDescriptionBox"
onClick={() => {
setIntroductionPage(introductionPage + 1);
}}
>
{t('description')}
</div>
<div className="testAgreement">
</div>
</div>
)}
<div
className="buttonWrapper"
style={{ display: introductionPage === 1 ? "" : "none" }}
>
<button onClick={() => {
setIntroductionPage(introductionPage + 1);
}}> {t('description')}</button>
<button onClick={() => {
setIntroductionPage(0);
}}>{t('agreement')}</button>
</div>
</div>{" "}
<Footer />
</div>
);
};
export default MainPage;
Here is the Header.js
import React, { useCallback, useContext } from "react";
import { useMainPageContext } from "../Hooks/mainPageContext";
import { useTranslation } from 'react-i18next';
const Header = () => {
const { t, i18n } = useTranslation();
const context = useMainPageContext();
const { onSetLanguage } = context;
const toggleLanguage = useCallback((lng) => {
i18n.changeLanguage(lng);
onSetLanguage(lng);
}, [i18n, onSetLanguage]);
const currentLanguage = i18n.language;
return (
<div className="header">
<h1
style={{
display: "flex",
flexFlow:"row",
alignItems:"center",
width: "calc(100% - 10%)",
height: "4vh",
backgroundColor: "white",
paddingTop:"0",
padding: "2.5%",
paddingLeft: "5%",
paddingRight: "5%",
justifyContent:"space-between"
}}
>
<div style={{display:"flex", color: "#F5821F",}}>
<img src={require("../Images/cmghLogo.png")} style={{width:"50%", height:"7.5%", marginTop:"0vh"}} alt="logo"/>
<div style={{ top: "0", margin: "0vh", marginLeft:"2vw", width:" 100%", fontSize:"3vw"}}>中心</div>
</div>
<div>
<header>
<button onClick={() => toggleLanguage('en')} disabled={currentLanguage === 'en'}>English</button>
<button onClick={() => toggleLanguage('tw')} disabled={currentLanguage === 'tw'}>中文</button>
</header>
</div>
</h1>
</div>
);
};
export default Header;
The i18n.js did not set properly.
so that failed to read the translation key-value pair.
After I changed to install and using "i18next-http-backend" plugin, modified the i18n.js, the problem is fixed as the following:
import i18n from 'i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
i18n
// load translation using http -> see /public/locales
// learn more: https://github.com/i18next/i18next-http-backend
.use(Backend)
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
fallbackLng: 'en',
debug: true,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
});
export default i18n;

in MERN, Response given and using useState to update new state with new fetched data, but not visually visible in my website even though logic works

By using console.log(responseData.places) I have checked the fetching works since I am using a hook for this and seems to work fine until I setLoadedPlaces with is the method I use to update the loadedPlaces which I later use to get the values to fill the frontend part of the website.
This is the output I get from this console.log I did and the values are correct.
[{…}]
0: address: "sis se puede
busrespect: 'tu puedes',
creator: "6384e2f543f63be1c560effa"
description: "al mundial"
id: "6384e30243f63be1c560f000"
image:"https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Empire_State_Building_%28aerial_view%29.jpg/400px-Empire_State_Building_%28aerial_view%29.jpg"location: {lat: -12.086158, lng: -76.898019}
title: "Peru"
__v: 0
_id: "6384e30243f63be1c560f000"[[Prototype]]:
Objectlength: 1[[Prototype]]: Array(0)
So after this this the code I have in the frontend (SINCE the backend works properly) Let me know if you have any doubts with this logic
This is UserPlaces.js
import React, {useState, useEffect } from 'react';
import PlaceList from '../components/PlaceList';
import { useParams } from 'react-router-dom';
import { useHttpClient } from '../../shared/hooks/http-hook';
import ErrorModal from '../../shared/components/UIElements/ErrorModal';
import LoadingSpinner from '../../shared/components/UIElements/LoadingSpinner';
const UserPlaces = () => {
const {loadedPlaces, setLoadedPlaces} = useState();
const {isLoading, error, sendRequest, clearError } = useHttpClient();
const userId = useParams().userId;
useEffect(() => {
const fetchPlaces = async () => {
try {
const responseData = await sendRequest(
`http://localhost:5000/api/places/user/${userId}`
);
console.log(responseData.bus_stops)
setLoadedPlaces(responseData.bus_stops);
} catch (err) {}
};
fetchPlaces();
}, [sendRequest, userId]);
return (
<React.Fragment>
<ErrorModal error={error} onClear={clearError} />
{isLoading && (
<div className="center">
<LoadingSpinner />
</div>
)}
{!isLoading && loadedPlaces && <PlaceList items={loadedPlaces} />}
</React.Fragment>
);
};
export default UserPlaces;
This is Place-List.js
import React from 'react';
import "./PlaceList.css"
import Card from '../../shared/components/UIElements/Card'
import PlaceItem from './PlaceItem';
import Button from '../../shared/components/FormElements/Button';
const PlaceList = props => {
if (props.items.length === 0) {
return (
<div className='place-list-center'>
<Card>
<h2>No bus stops available. Be the first one to create one!</h2>
<Button to='/places/new'> Create Bus Stop </Button>
</Card>
</div>
);
}
return (
<ul className="place-list">
{props.items.map(bus_stops => (
<PlaceItem
key={bus_stops.id}
id={bus_stops.id}
image={bus_stops.image}
title={bus_stops.title}
busrespect={bus_stops.busrespect}
description={bus_stops.description}
address={bus_stops.address}
creatorId={bus_stops.creator}
coordinates={bus_stops.location}
/>
))}
</ul>
);
};
export default PlaceList;
This is PlaceItem.js
import React, { useState } from 'react';
import { useContext } from 'react';
import Card from '../../shared/components/UIElements/Card';
import Button from '../../shared/components/FormElements/Button';
import Modal from '../../shared/components/UIElements/Modal';
import Map from '../../shared/components/UIElements/Map';
import {AuthContext} from '../../shared//context/auth-context'
import "./PlaceItem.css";
const PlaceItem = props => {
const auth = useContext(AuthContext);
const [showMap, setShowMap] = useState(false);
const [showConfirmModal, setShowConfirmModal] = useState(false);
const openMapHandler = () => setShowMap(true);
const closeMapHandler = () => setShowMap(false);
const showDeleteWarningHandler = () => {
setShowConfirmModal(true);
};
const cancelDeleteHandler = () => {
setShowConfirmModal(false);
};
const confirmDeleteHandler = () => {
setShowConfirmModal(false); //when clicked close the new Modal
console.log('DELETING...');
};
return (
<React.Fragment>
<Modal show={showMap}
onCancel={closeMapHandler}
header={props.address}
contentClass="place-item__modal-content"
footerClass="place-item__modal-actions"
footer={<Button onClick={closeMapHandler}>Close </Button>}
>
<div className='map-container'>
<Map center={props.coordinates} zoom={16}/> {/* Should be props.coordinates but we writing default data for now until geocoding solved. */}
</div>
</Modal>
<Modal
show={showConfirmModal}
onCancel={cancelDeleteHandler}
header="Are you entirely sure?"
footerClass="place-item__modal-actions"
footer={
<React.Fragment>
<Button inverse onClick={cancelDeleteHandler}>
CANCEL
</Button>
<Button danger onClick={confirmDeleteHandler}>
DELETE
</Button>
</React.Fragment>
}
>
<p>
Do you want to proceed and delete this place? Please note that it
can't be undone thereafter.
</p>
</Modal>
<li className='"place=item'>
<Card className="place-item__content">
<div className='place-item__image'>
<img src={props.image} alt={props.title}/>
</div>
<div className='place-item__info'>
<h2>{props.title}</h2>
<h3>{props.address}</h3>
<p>{props.description}</p>
<p>{props.busrespect}</p>
</div>
<div className='place-item__actions'>
<Button inverse onClick={openMapHandler}> VIEW ON MAP</Button>
{auth.isLoggedIn && (<Button to={`/places/${props.id}`}> EDIT</Button> )}
{auth.isLoggedIn &&<Button danger onClick={showDeleteWarningHandler}> DELETE </Button>}
</div>
</Card>
</li>
</React.Fragment>
);
};
export default PlaceItem;
This is auth-context:
import { createContext } from "react";
export const AuthContext = createContext({
isLoggedIn: false,
userId: null,
login: () => {},
logout: () => {}});
This is is Modal.js
import React from 'react';
import ReactDOM from 'react-dom';
import Backdrop from './Backdrop';
import { CSSTransition } from 'react-transition-group';
import './Modal.css';
const ModalOverlay = props => {
const content =(
<div className={`modal ${props.className}`} style = {props.style}>
<header className={`modal__header ${props.headerClass}`}>
<h2>{props.header}</h2>
</header>
<form
onSubmit={
props.onSubmit ? props.onSubmit : event => event.preventDefault()
}
>
<div className={`modal__content ${props.contentClass}`}>
{props.children}
</div>
<footer className={`modal__content ${props.footerClass}`}>
{props.footer}
</footer>
</form>
</div>
);
return ReactDOM.createPortal(content, document.getElementById('modal-hook'));
};
const Modal = props => {
return (
<React.Fragment>
{props.show && <Backdrop onClick={props.onCancel} />}
<CSSTransition in={props.show}
mountOnEnter
unmountOnExit
timeout={200}
classNames="modal"
>
<ModalOverlay {...props}/>
</CSSTransition>
</React.Fragment>
);
};
export default Modal;
Also Trust the routing is correct since I have checked it already and I am just wondering if the logic in REACT with loadedPlaces, PlaceItema and PlaceList makes sense and it working. Let me know please. It will be really helpful.
Summary: Not getting any error but no visual data appears in the scren just the header of my website and the background (rest is empty) even though logic is functional.
const {loadedPlaces, setLoadedPlaces} = useState();
change the above line to
const [loadedPlaces, setLoadedPlaces] = useState();

I want split one component in 2 components React JS

I'v a problem because I would split one component in two components.
I build my component with a search bar with autocomplete and the map with a pin chosen with the search bar. And me, I would one component with searcbar and an other with map who comunicate the date between them.
But I don't no how make this ..
Somebody could help me ?
Sorry for my Enlish, I'm French
Here is the code of my component:
import React, { useState, createContext } from 'react';
import {Map, Marker, GoogleApiWrapper} from 'google-maps-react';
import PlacesAutocomplete, {
geocodeByAddress,
getLatLng,
} from 'react-places-autocomplete';
import Child2 from '../Child2';
const Location = createContext();
function Searchbar() {
const [address, setAdress] = useState("")
const [coordinates, setCoordinates] = useState({
lat: null,
lng: null
})
const handleSelect = (value, props) => {
const results = await geocodeByAddress(value);
const ll = await getLatLng(results[0])
console.log(ll)
setAdress(value)
setCoordinates(ll)
props.OnSelectPlace(ll)
}
return (
<div className="Searchbar">
<p>{coordinates.lat}</p>
<p>{coordinates.lng}</p>
<p>{address}</p>
<PlacesAutocomplete
value={address}
onChange={setAdress}
onSelect={handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<input
{...getInputProps({
placeholder: 'Search Places ...',
className: 'location-search-input',
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#E4E4E4', cursor: 'pointer' }
: { backgroundColor: '#F8F8F8', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
</div>
);
}
export {Location};
export default GoogleApiWrapper({
apiKey: ("secret_code_api_google_map")
})(Searchbar)
Build two separate components one for the map and other for the searchbar. Then pass date as a prop to the second component.

How to add a video to React Responsive Carousel Npm Package?

I am trying to create a Carousel of images and embedded Youtube videos (the first item is a youtube video and the rest are images)
I am using the React Responsive Carusel npm package but I can't find a way to create the carousel I want without bugs.
I saw a solution over here but it's only for videos.
Here is my code at the moment:
import React from 'react'
import 'react-responsive-carousel/lib/styles/carousel.min.css' // requires a loader
import { Carousel } from 'react-responsive-carousel'
import ReactPlayer from 'react-player'
const ModalImagesPreview = () => {
return (
<div>
<Carousel>
<div>
<ReactPlayer
url='https://www.youtube.com/watch?v=ysz5S6PUM-U'
volume='1'
muted
width='100%'
playing={true}
/>
</div>
<div>
<img src='https://cdn.dribbble.com/users/2146089/screenshots/12387473/media/bf9ffb522fe68ba57ebdc62bc3f16cc5.png' />
</div>
<div>
<img src='https://cdn.dribbble.com/users/427857/screenshots/12318706/media/f30f662dbf160022412812881b2afb43.jpg' />
</div>
</Carousel>
</div>
)
}
export default ModalImagesPreview
Thanks for the helpers!
Here is what I found on the react-responsive-carousel website
import 'react-responsive-carousel/lib/styles/carousel.min.css'; // requires a loader
import React from 'react';
import ReactPlayer from 'react-player';
import { Carousel } from 'react-responsive-carousel';
import { PropTypes } from 'prop-types';
import { Grid, makeStyles } from '#material-ui/core';
const DUMMY_VIDEOS = [
{
_id: '5fd025a181e2c80897c14ae1',
videoUrl: 'https://www.youtube.com/embed/AVn-Yjr7kDc'
}
];
const useStyles = makeStyles(theme => ({
carousel: {
margin: theme.spacing(2)
}
}));
const YoutubeSlide = ({ url, isSelected }) => (
<ReactPlayer width="100%" height="276px" url={url} playing={isSelected} />
);
const CarouselVideo = ({ data }) => {
const classes = useStyles();
const customRenderItem = (item, props) => (
<item.type {...item.props} {...props} />
);
const getVideoThumb = videoId =>`https://img.youtube.com/vi/${videoId}/default.jpg`;
const getVideoId = url =>url.substr('https://www.youtube.com/watch?v='.length, url.length);
const customRenderThumb = children =>
children.map(item => {
const videoId = getVideoId(item.props.url);
return <img key={videoId} src={getVideoThumb(videoId)} />;
});
return (
<Grid item md={6} xs={12}>
<Carousel
autoPlay={false}
className={classes.carousel}
emulateTouch={true}
showArrows={true}
showThumbs={true}
showStatus={false}
infiniteLoop={true}
renderItem={customRenderItem}
renderThumbs={customRenderThumb}
>
{data.map(v => (
<YoutubeSlide
url={v.videoUrl}
muted
playing={false}
key={v._id ? v._id : v.id}
/>
))}
</Carousel>
</Grid>
);
};
YoutubeSlide.propTypes = {
url: PropTypes.string,
isSelected: PropTypes.bool
};
CarouselVideo.propTypes = {
data: PropTypes.array
};
CarouselVideo.defaultProps = {
data: DUMMY_VIDEOS
};
export default CarouselVideo;
Last step is to call this CarouselVideo where you want to render with your data as props or just call it without passint anythind => this will display the dummy videos I added there.
So you can call it like the below:
// DisplayVideo.js file with default videos as shown below
const DisplayVideo = () => {
render( <CarouselVideo />)
}
// or with your data
const DisplayVideo = ({PASS_YOU_DATA_HERE}) => {
render( <CarouselVideo data={PASS_YOU_DATA_HERE} />)
}
Result:
(source: https://www.npmjs.com/package/react-responsive-carousel)

how to set center on StandaloneSearchBox in react google maps

i'm using react google maps standalonesearchbox,every thing is ok,but how can i show first near by location in google map search hints(places),generally when we use map with search box then we attach both each other but here i didn't add map.
so here my question is how can i set center or show nearby search first on google places search hints.
here is my code
import React from 'react';
import {connect} from 'react-redux';
import { Input,Icon} from 'antd';
import 'antd/dist/antd.css';
import {pickupHandler,pickupAddHandler,dropoffHandler} from '../actions';
import config from '../../../config'
const { compose, withProps, lifecycle,withHandlers } = require("recompose");
const {
withScriptjs,
} = require("react-google-maps");
const { StandaloneSearchBox } = require("react-google-maps/lib/components/places/StandaloneSearchBox");
const SearchBox = compose(
withProps({
googleMapURL: config.MapApi,
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
}),
lifecycle({
componentWillMount() {
const refs = {}
this.setState({
onSearchBoxMounted: ref => {
refs.searchBox = ref;
},
onBoundsChanged: () => {
this.setState({
bounds: refs.map.getBounds(),
center: refs.map.getCenter(),
})
},
onPlacesChanged: () => {
const places = refs.searchBox.getPlaces();
places.map(({ place_id, formatted_address, geometry: { location } }) =>{
this.props.latlngHandler({lat:location.lat(),lng:location.lng()})
this.props.AddressHandler(formatted_address)
})
this.setState({
places,
});
},
suffix: () =>{
this.props.AddressHandler('')
this.props.latlngHandler(false);
}
})
},
}),
withHandlers(() => {
return{
cutPickIcon:<Icon type="close-circle" />
}
}),
withScriptjs
)(props =>
<div data-standalone-searchbox="">
<StandaloneSearchBox
ref={props.onSearchBoxMounted}
bounds={props.bounds}
onBoundsChanged={props.onBoundsChanged}
onPlacesChanged={props.onPlacesChanged}
>
<Input
prefix={<Icon type="environment-o" style={props.name === 'pick' ? { color: '#EA4335' }: { color: '#00E64D' }} />}
type="text"
placeholder={props.placeHoler}
onChange={props.Field}
onFocus={props.FocusGA}
value={props.Address}
className='input'
suffix={props.Suffix ? <Icon type="close-circle" onClick={props.suffix}/> :''}
/>
</StandaloneSearchBox>
</div>
);
export default connect(null,{pickupAddHandler,pickupHandler,dropoffHandler})(SearchBox)
You can use the maps geocode to set bounds prop on StandaloneSearchBox.
Please refer to my answer on this post.
https://stackoverflow.com/a/53396781/1661712

Resources