反応アプリにGoogleマップを加えてください
134374 ワード
今すぐ私の電子メールリストを購読http://jauyeung.net/subscribe/
に私について来てください
反応は、インタラクティブなフロントエンドのWebアプリを作成するためのシンプルなライブラリです.その機能セットは基本的です.それはWebアプリケーションを構築するためのコンポーネントベースのアーキテクチャを提供します.各コンポーネントは、アプリケーション内の小さなものをし、彼らはお互いに入れ子にすることができますまたは並んで置くことができます.このため、サードパーティライブラリを追加するのは簡単です.Googleマップは、開発者がそれのためのコンポーネントを書いているので、反応アプリに組み込むことができる人気のある地図システムです.
この物語では、我々は、これらのライブラリを使用してアドレス帳のアプリをビルドし、プラスのブートストラップは、フォームを作成する上でこれらのライブラリとの偉大な統合をしています.我々はアプリケーションを足場に作成する反応アプリを実行する必要が起動します.我々は走る
すべての連絡先を表示し、各行に編集して削除ボタンを編集したり、各連絡先を削除するテーブルがあります.連絡先は、中央の場所に連絡先を格納するには、中央reduxストアに格納されます.反応ルータはルーティングに使用されます.
コンタクトは、JSONサーバパッケージを使用して生成されたバックエンドに保存されますhttps://github.com/typicode/json-server . これは、Googleのマップの連絡先の場所を表示する必要があります.ユーザーが各列でマップボタンをクリックすると、ユーザーはモーダルで地図を表示します.
フォームの検証のために、サードパーティライブラリを使用する必要があります.フォルククとユウhttps://github.com/jaredpalmer/formik and https://github.com/jquense/yup 私たちはほとんどのフォームの検証ニーズの世話をするために一緒に偉大な作品.FormIkフォームを構築し、エラーを表示し、フォームの値の変更を処理します.yup私たちのフォームフィールドを検証するためのスキーマを書きましょう.これは、ほとんどの何かをチェックすることができます電子メールのような一般的な検証コードや必要なフィールドを組み込み機能としてご利用いただけます.また、国によって郵便番号形式のような他のフィールドに依存するフィールドをチェックすることもできます.ブートストラップフォームはFormickとYUPとシームレスに使用できます.
使用する
それが完了したら、いくつかのライブラリをインストールする必要があります.上記のライブラリをインストールするには
我々はすべてのライブラリをインストールしたので、我々はアプリを構築を開始することができます.すべてのファイルは
別のファイルを作成します
イン
次にコンタクトフォームを作ります.これは我々のアプリの最もロジックの一部です.ファイルを作成します
フォームの検証メッセージを表示するには、
パラメータ
次に、Googleマップのコンポーネントを使用して、連絡先の場所を表示します.ファイルを作る
イン
このコンポーネントのすべての小道具を
次に、ファイルを作成します
イン
それから、私たちは
それから、私たちは
最後に
今我々は実行してアプリケーションを実行することができます
endを開始するには、まず
に私について来てください
反応は、インタラクティブなフロントエンドのWebアプリを作成するためのシンプルなライブラリです.その機能セットは基本的です.それはWebアプリケーションを構築するためのコンポーネントベースのアーキテクチャを提供します.各コンポーネントは、アプリケーション内の小さなものをし、彼らはお互いに入れ子にすることができますまたは並んで置くことができます.このため、サードパーティライブラリを追加するのは簡単です.Googleマップは、開発者がそれのためのコンポーネントを書いているので、反応アプリに組み込むことができる人気のある地図システムです.
この物語では、我々は、これらのライブラリを使用してアドレス帳のアプリをビルドし、プラスのブートストラップは、フォームを作成する上でこれらのライブラリとの偉大な統合をしています.我々はアプリケーションを足場に作成する反応アプリを実行する必要が起動します.我々は走る
npx create-react-app address-book
最初のファイルでアプリケーションプロジェクトフォルダーを作成するには.アプリは、連絡先を表示し、連絡先を追加するには、モーダルを開くことができますホームページがあります.すべての連絡先を表示し、各行に編集して削除ボタンを編集したり、各連絡先を削除するテーブルがあります.連絡先は、中央の場所に連絡先を格納するには、中央reduxストアに格納されます.反応ルータはルーティングに使用されます.
コンタクトは、JSONサーバパッケージを使用して生成されたバックエンドに保存されますhttps://github.com/typicode/json-server . これは、Googleのマップの連絡先の場所を表示する必要があります.ユーザーが各列でマップボタンをクリックすると、ユーザーはモーダルで地図を表示します.
フォームの検証のために、サードパーティライブラリを使用する必要があります.フォルククとユウhttps://github.com/jaredpalmer/formik and https://github.com/jquense/yup 私たちはほとんどのフォームの検証ニーズの世話をするために一緒に偉大な作品.FormIkフォームを構築し、エラーを表示し、フォームの値の変更を処理します.yup私たちのフォームフィールドを検証するためのスキーマを書きましょう.これは、ほとんどの何かをチェックすることができます電子メールのような一般的な検証コードや必要なフィールドを組み込み機能としてご利用いただけます.また、国によって郵便番号形式のような他のフィールドに依存するフィールドをチェックすることもできます.ブートストラップフォームはFormickとYUPとシームレスに使用できます.
使用する
react-google-maps
当社の反応アプリにGoogleマップを組み込むにはhttps://www.npmjs.com/package/react-google-maps . それは人気があり、それが反応の最新バージョンで動作するように積極的に維持されます.また使いやすい.それが完了したら、いくつかのライブラリをインストールする必要があります.上記のライブラリをインストールするには
npm i axios bootstrap formik react-bootstrap react-redux react-router-dom yup react-google-maps
. AxiosはHTTPリクエストをバックエンドにするためのHTTPクライアントです.react-router-dom
は、最新のバージョンの反応ルータのパッケージ名です.我々はすべてのライブラリをインストールしたので、我々はアプリを構築を開始することができます.すべてのファイルは
src
さもなければ言及する以外のフォルダ.最初に、我々はRedux店で働きます.ファイルを作成しますactionCreator.js
にsrc
フォルダを追加し、次のように追加します.import { SET_CONTACTS } from './actions';
const setContacts = (contacts) => {
return {
type: SET_CONTACTS,
payload: contacts
}
};
export { setContacts };
これは、ストア内の連絡先を格納するためのアクションを作成するためのアクション作成です.別のファイルを作成します
actions.js
を追加します.const SET_CONTACTS = 'SET_CONTACTS';
export { SET_CONTACTS };
これには、アクションをディスパッチするための型定数があります.イン
App.js
, 既存のものを置き換えます.import React from 'react';
import { Router, Route, Link } from "react-router-dom";
import HomePage from './HomePage';
import { createBrowserHistory as createHistory } from 'history'
import Navbar from 'react-bootstrap/Navbar';
import Nav from 'react-bootstrap/Nav';
import './App.css';
const history = createHistory();
function App() {
return (
<div className="App">
<Router history={history}>
<Navbar bg="primary" expand="lg" variant="dark" >
<Navbar.Brand href="#home">Address Book App</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
<Nav.Link href="/">Home</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
<Route path="/" exact component={HomePage} />
</Router>
</div>
);
}
export default App;
ここでは、ナビゲーションバーを追加し、我々のルートは、反応ルータによってルーティング表示されます.インApp.css
, 既存のコードを置き換えます..App {
text-align: center;
}
テキストを中心に.次にコンタクトフォームを作ります.これは我々のアプリの最もロジックの一部です.ファイルを作成します
ContactForm.js
を追加します.import React from 'react';
import { Formik } from 'formik';
import Form from 'react-bootstrap/Form';
import Col from 'react-bootstrap/Col';
import InputGroup from 'react-bootstrap/InputGroup';
import Button from 'react-bootstrap/Button';
import * as yup from 'yup';
import { COUNTRIES } from './exports';
import PropTypes from 'prop-types';
import { addContact, editContact, getContacts } from './requests';
import { connect } from 'react-redux';
import { setContacts } from './actionCreators';
const schema = yup.object({
firstName: yup.string().required('First name is required'),
lastName: yup.string().required('Last name is required'),
address: yup.string().required('Address is required'),
city: yup.string().required('City is required'),
region: yup.string().required('Region is required'),
country: yup.string().required('Country is required').default('Afghanistan'),
postalCode: yup
.string()
.when('country', {
is: 'United States',
then: yup.string().matches(/^[0-9]{5}(?:-[0-9]{4})?$/, 'Invalid postal code'),
})
.when('country', {
is: 'Canada',
then: yup.string().matches(/^[A-Za-z]\d[A-Za-z][ -\]?\d[A-Za-z]\d$/, 'Invalid postal code'),
})
.required(),
phone: yup
.string()
.when('country', {
is: country => ["United States", "Canada"].includes(country),
then: yup.string().matches(/^[2-9]\d{2}[2-9]\d{2}\d{4}$/, 'Invalid phone nunber')
})
.required(),
email: yup.string().email('Invalid email').required('Email is required'),
age: yup.number()
.required('Age is required')
.min(0, 'Minimum age is 0')
.max(200, 'Maximum age is 200'),
});
function ContactForm({
edit,
onSave,
setContacts,
contact,
onCancelAdd,
onCancelEdit,
}) {
const handleSubmit = async (evt) => {
const isValid = await schema.validate(evt);
if (!isValid) {
return;
}
if (!edit) {
await addContact(evt);
}
else {
await editContact(evt);
}
const response = await getContacts();
setContacts(response.data);
onSave();
}
return (
<div className="form">
<Formik
validationSchema={schema}
onSubmit={handleSubmit}
initialValues={contact || {}}
>
{({
handleSubmit,
handleChange,
handleBlur,
values,
touched,
isInvalid,
errors,
}) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Row>
<Form.Group as={Col} md="12" controlId="firstName">
<Form.Label>First name</Form.Label>
<Form.Control
type="text"
name="firstName"
placeholder="First Name"
value={values.firstName || ''}
onChange={handleChange}
isInvalid={touched.firstName && errors.firstName}
/>
<Form.Control.Feedback type="invalid">
{errors.firstName}
</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="12" controlId="lastName">
<Form.Label>Last name</Form.Label>
<Form.Control
type="text"
name="lastName"
placeholder="Last Name"
value={values.lastName || ''}
onChange={handleChange}
isInvalid={touched.firstName && errors.lastName}
/><Form.Control.Feedback type="invalid">
{errors.lastName}
</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="12" controlId="address">
<Form.Label>Address</Form.Label>
<InputGroup>
<Form.Control
type="text"
placeholder="Address"
aria-describedby="inputGroupPrepend"
name="address"
value={values.address || ''}
onChange={handleChange}
isInvalid={touched.address && errors.address}
/>
<Form.Control.Feedback type="invalid">
{errors.address}
</Form.Control.Feedback>
</InputGroup>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col} md="12" controlId="city">
<Form.Label>City</Form.Label>
<Form.Control
type="text"
placeholder="City"
name="city"
value={values.city || ''}
onChange={handleChange}
isInvalid={touched.city && errors.city}
/><Form.Control.Feedback type="invalid">
{errors.city}
</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="12" controlId="region">
<Form.Label>Region</Form.Label>
<Form.Control
type="text"
placeholder="Region"
name="region"
value={values.region || ''}
onChange={handleChange}
isInvalid={touched.region && errors.region}
/>
<Form.Control.Feedback type="invalid">
{errors.region}
</Form.Control.Feedback>
</Form.Group><Form.Group as={Col} md="12" controlId="country">
<Form.Label>Country</Form.Label>
<Form.Control
as="select"
placeholder="Country"
name="country"
onChange={handleChange}
value={values.country || ''}
isInvalid={touched.region && errors.country}>
{COUNTRIES.map(c => <option key={c} value={c}>{c}</option>)}
</Form.Control>
<Form.Control.Feedback type="invalid">
{errors.country}
</Form.Control.Feedback>
</Form.Group><Form.Group as={Col} md="12" controlId="postalCode">
<Form.Label>Postal Code</Form.Label>
<Form.Control
type="text"
placeholder="Postal Code"
name="postalCode"
value={values.postalCode || ''}
onChange={handleChange}
isInvalid={touched.postalCode && errors.postalCode}
/><Form.Control.Feedback type="invalid">
{errors.postalCode}
</Form.Control.Feedback>
</Form.Group><Form.Group as={Col} md="12" controlId="phone">
<Form.Label>Phone</Form.Label>
<Form.Control
type="text"
placeholder="Phone"
name="phone"
value={values.phone || ''}
onChange={handleChange}
isInvalid={touched.phone && errors.phone}
/><Form.Control.Feedback type="invalid">
{errors.phone}
</Form.Control.Feedback>
</Form.Group><Form.Group as={Col} md="12" controlId="email">
<Form.Label>Email</Form.Label>
<Form.Control
type="text"
placeholder="Email"
name="email"
value={values.email || ''}
onChange={handleChange}
isInvalid={touched.email && errors.email}
/><Form.Control.Feedback type="invalid">
{errors.email}
</Form.Control.Feedback>
</Form.Group><Form.Group as={Col} md="12" controlId="age">
<Form.Label>Age</Form.Label>
<Form.Control
type="text"
placeholder="Age"
name="age"
value={values.age || ''}
onChange={handleChange}
isInvalid={touched.age && errors.age}
/><Form.Control.Feedback type="invalid">
{errors.age}
</Form.Control.Feedback>
</Form.Group>
</Form.Row>
<Button type="submit" style={{ 'marginRight': '10px' }}>Save</Button>
<Button type="button" onClick={edit ? onCancelEdit : onCancelAdd}>Cancel</Button>
</Form>
)}
</Formik>
</div>
);
}
ContactForm.propTypes = {
edit: PropTypes.bool,
onSave: PropTypes.func,
onCancelAdd: PropTypes.func,
onCancelEdit: PropTypes.func,
contact: PropTypes.object
}
const mapStateToProps = state => {
return {
contacts: state.contacts,
}
}
const mapDispatchToProps = dispatch => ({
setContacts: contacts => dispatch(setContacts(contacts))
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(ContactForm);
私たちは私たちのブートストラップでここで私たちの連絡先を構築を容易にするFormekを使用しますForm
入れ子になったコンポーネントFormik
フォルムの使用できるコンポーネントhandleChange
, handleSubmit
, values
, touched
and errors
パラメータ.handleChange
は、自分自身でコードを書くことなく入力からデータフィールドデータを更新させる関数です.handleSubmit
関数は、onSubmit
ハンドラFormik
コンポーネント.関数のパラメータは、フィールド名をキーとして入力したデータですname
各フィールドの属性と各フィールドの値を、それらのキーの値として指定します.注意してくださいvalue
プロップ,我々は||''
それで、我々は未定義の値を得ないで、制御されないフォーム警告が引き起こされるのを防ぎます.フォームの検証メッセージを表示するには、
isInvalid
各プロップForm.Control
コンポーネント.The schema
オブジェクトは何ですかFormik
フォームの検証をチェックします.の議論required
関数は検証エラーメッセージです.The second argument of the matches
, min
and max
関数も妥当性検査メッセージです.パラメータ
ContactForm
関数は小道具であり、我々はHomePage
後でビルドするコンポーネント.The handleSubmit
関数は、データが有効かどうかをチェックし、もしそれがあれば、それが追加されているか、連絡先を編集しているかどうかに従って保存されます.保存が成功したら、私たちは店と電話で連絡先を設定しますonSave
PROPは、モードを閉じる機能です.モーダルは、ホームページで定義されます.mapStateToProps
関数名が示すように、我々のコンポーネントの小道具に直接状態をマップできるように、Retrixによって提供される関数です.mapDispatchToProps
コンポーネントの小道具の関数を呼び出すことができますsetContacts
我々が定義したように行動を送るactionCreators.js
次に、ファイルを作成しますexports.js
, 設定export const COUNTRIES = ["Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Anguilla", "Antigua & Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas"
, "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia & Herzegovina", "Botswana", "Brazil", "British Virgin Islands"
, "Brunei", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Chad", "Chile", "China", "Colombia", "Congo", "Cook Islands", "Costa Rica"
, "Cote D Ivoire", "Croatia", "Cruise Ship", "Cuba", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea"
, "Estonia", "Ethiopia", "Falkland Islands", "Faroe Islands", "Fiji", "Finland", "France", "French Polynesia", "French West Indies", "Gabon", "Gambia", "Georgia", "Germany", "Ghana"
, "Gibraltar", "Greece", "Greenland", "Grenada", "Guam", "Guatemala", "Guernsey", "Guinea", "Guinea Bissau", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India"
, "Indonesia", "Iran", "Iraq", "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kuwait", "Kyrgyz Republic", "Laos", "Latvia"
, "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Mauritania"
, "Mauritius", "Mexico", "Moldova", "Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Namibia", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia"
, "New Zealand", "Nicaragua", "Niger", "Nigeria", "Norway", "Oman", "Pakistan", "Palestine", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal"
, "Puerto Rico", "Qatar", "Reunion", "Romania", "Russia", "Rwanda", "Saint Pierre & Miquelon", "Samoa", "San Marino", "Satellite", "Saudi Arabia", "Senegal", "Serbia", "Seychelles"
, "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "South Africa", "South Korea", "Spain", "Sri Lanka", "St Kitts & Nevis", "St Lucia", "St Vincent", "St. Lucia", "Sudan"
, "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor L'Este", "Togo", "Tonga", "Trinidad & Tobago", "Tunisia"
, "Turkey", "Turkmenistan", "Turks & Caicos", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "United States Minor Outlying Islands", "Uruguay"
, "Uzbekistan", "Venezuela", "Vietnam", "Virgin Islands (US)", "Yemen", "Zambia", "Zimbabwe"];
これらは国の国の形でフィールドです.次に、Googleマップのコンポーネントを使用して、連絡先の場所を表示します.ファイルを作る
MapComponent.js
を追加します.import React from "react";
import { compose, withProps } from "recompose";
import { GOOGLE_API_KEY } from "./requests";import {
withGoogleMap,
GoogleMap,
Marker,
withScriptjs,
} from "react-google-maps";const MapComponent = compose(
withProps({
googleMapURL: `[https://maps.googleapis.com/maps/api/js?key=${GOOGLE_API_KEY}&v=3.exp&libraries=geometry,drawing,places`](https://maps.googleapis.com/maps/api/js?key=${GOOGLE_API_KEY}&v=3.exp&libraries=geometry,drawing,places`),
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)(({ lat, lng }) => (
<GoogleMap defaultZoom={8} defaultCenter={{ lat, lng }}>
<Marker position={{ lat, lng }} />
</GoogleMap>
));
export default MapComponent;
引数withProps
ファンクションコールはGoogleMap
コンポーネントwithScriptjs
GoogleマップからJavaScriptファイルを読み込みます.lat
and lng
我々は、緯度と経度でそれぞれの場所を表示するコンポーネントに渡す小道具です.イン
HomePage.js
, 私たちは置きました.import React from "react";
import { useState, useEffect } from "react";
import Table from "react-bootstrap/Table";
import ButtonToolbar from "react-bootstrap/ButtonToolbar";
import Button from "react-bootstrap/Button";
import Modal from "react-bootstrap/Modal";
import ContactForm from "./ContactForm";
import "./HomePage.css";
import MapComponent from "./MapComponent";
import { connect } from "react-redux";
import { getContacts, deleteContact, getLatLng } from "./requests";function HomePage() {
const [openAddModal, setOpenAddModal] = useState(false);
const [openEditModal, setOpenEditModal] = useState(false);
const [openMapModal, setOpenMapModal] = useState(false);
const [initialized, setInitialized] = useState(false);
const [loc, setLoc] = useState({
lat: 0,
lng: 0,
});
const [selectedContact, setSelectedContact] = useState({});
const [contacts, setContacts] = useState([]);
const openModal = () => {
setOpenAddModal(true);
};
const closeModal = () => {
setOpenAddModal(false);
setOpenEditModal(false);
setOpenMapModal(false);
getData();
};
const cancelAddModal = () => {
setOpenAddModal(false);
};
const editContact = contact => {
setSelectedContact(contact);
setOpenEditModal(true);
};
const cancelEditModal = () => {
setOpenEditModal(false);
};
const getData = async () => {
const response = await getContacts();
setContacts(response.data);
setInitialized(true);
};
const deleteSelectedContact = async id => {
await deleteContact(id);
getData();
};
const openMap = async contact => {
try {
const address = `${contact.addressLineOne}, ${contact.addressLineTwo}, ${contact.city}, ${contact.country}`;
const response = await getLatLng(address);
const loc = response.data.results[0].geometry.location;
setLoc(loc);
setOpenMapModal(true);
} catch (ex) {
console.log(ex);
}
};
useEffect(() => {
if (!initialized) {
getData();
}
});
return (
<div className="home-page">
<h1>Contacts</h1>
<Modal show={openAddModal} onHide={closeModal}>
<Modal.Header closeButton>
<Modal.Title>Add Contact</Modal.Title>
</Modal.Header>
<Modal.Body>
<ContactForm
edit={false}
onSave={closeModal.bind(this)}
onCancelAdd={cancelAddModal}
/>
</Modal.Body>
</Modal> <Modal show={openEditModal} onHide={closeModal}>
<Modal.Header closeButton>
<Modal.Title>Edit Contact</Modal.Title>
</Modal.Header>
<Modal.Body>
<ContactForm
edit={true}
onSave={closeModal.bind(this)}
contact={selectedContact}
onCancelEdit={cancelEditModal}
/>
</Modal.Body>
</Modal> <Modal show={openMapModal} onHide={closeModal}>
<Modal.Header closeButton>
<Modal.Title>Map</Modal.Title>
</Modal.Header>
<Modal.Body>
<MapComponent
lat={loc.lat}
lng={loc.lng}
/>
</Modal.Body>
</Modal> <ButtonToolbar onClick={openModal}>
<Button variant="outline-primary">Add Contact</Button>
</ButtonToolbar>
<br />
<Table striped bordered hover>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Address</th>
<th>City</th>
<th>Country</th>
<th>Postal Code</th>
<th>Phone</th>
<th>Email</th>
<th>Age</th>
<th>Map</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{contacts.map(c => (
<tr key={c.id}>
<td>{c.firstName}</td>
<td>{c.lastName}</td>
<td>{c.address}</td>
<td>{c.city}</td>
<td>{c.country}</td>
<td>{c.postalCode}</td>
<td>{c.phone}</td>
<td>{c.email}</td>
<td>{c.age}</td>
<td>
<Button
variant="outline-primary"
onClick={openMap.bind(this, c)}
>
Map
</Button>
</td>
<td>
<Button
variant="outline-primary"
onClick={editContact.bind(this, c)}
>
Edit
</Button>
</td>
<td>
<Button
variant="outline-primary"
onClick={deleteSelectedContact.bind(this, c.id)}
>
Delete
</Button>
</td>
</tr>
))}
</tbody>
</Table>
</div>
);
}
const mapStateToProps = state => {
return {
contacts: state.contacts,
};
};
export default connect(
mapStateToProps,
null
)(HomePage);
これは、連絡先やボタンを追加するには、編集、および削除連絡先を表示するテーブルがあります.これは、1回目の負荷でデータを取得するgetData
関数呼び出しuseEffect
‘sコールバック関数.useEffect
‘s callbackはすべてのレンダリング業者に対して呼び出されますので、initialized
フラグを指定した場合にのみロードされ、true
.このコンポーネントのすべての小道具を
ContactForm
コンポーネント.議論をするonClick
ハンドラ関数は、コールする必要がありますbind
関数の引数と2番目の引数としての関数の引数bind
. 例えば、このファイルではeditContact.bind(this, c)
, どこc
はコンタクトオブジェクトです.The editContact
関数は以下のように定義される.const editContact = (contact) => {
setSelectedContact(contact);
setOpenEditModal(true);
}
c
はcontact
パラメータを渡します.次に、ファイルを作成します
HomePage.css
設定.home-page {
padding: 20px;
}
パディングを追加するにはイン
index.js
, 既存のコードを置き換えます.import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import \* as serviceWorker from './serviceWorker';
import { contactsReducer } from './reducers';
import { Provider } from 'react-redux'
import { createStore, combineReducers } from 'redux'const addressBookApp = combineReducers({
contacts: contactsReducer,
})const store = createStore(addressBookApp)ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root'));// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: [https://bit.ly/CRA-PWA](https://bit.ly/CRA-PWA)
serviceWorker.unregister();
我々は減速機を組み合わせて、ストアを作成し、それを私たちのアプリに注入Provider
コンポーネントは、我々はアプリのどこにでも使用できるように.それから、私たちは
reducers.js
, を追加します.import { SET_CONTACTS } from './actions';
function contactsReducer(state = {}, action) {
switch (action.type) {
case SET_CONTACTS:
state = JSON.parse(JSON.stringify(action.payload));
return state;
default:
return state
}
}
export { contactsReducer };
これは、我々が提供するプロップを呼び出すことによって我々が派遣する連絡先を格納する還元器ですmapDispatchToProps
コンポーネントの機能.それから、私たちは
requests.js
, を追加します.const APIURL = "http://localhost:3000";
const MAPURL = "https://maps.googleapis.com/maps/api/geocode/json?address=";
const axios = require("axios");
export const GOOGLE_API_KEY = "your API key";
export const getContacts = () => axios.get(`${APIURL}/contacts`);
export const addContact = data => axios.post(`${APIURL}/contacts`, data);
export const editContact = data =>
axios.put(`${APIURL}/contacts/${data.id}`, data);
export const deleteContact = id => axios.delete(`${APIURL}/contacts/${id}`);
export const getLatLng = address => {
return axios.get(
`${MAPURL}${encodeURIComponent(address)}&key=${GOOGLE_API_KEY}`
);
};
これらの関数は、私たちのHTTPリクエストをバックエンドに保存し、削除する連絡先を作っています.最後に
public/index.html
, 既存のコードを置き換えます.<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="logo192.png" />
<link rel="manifest" crossorigin="use-credentials" href="%PUBLIC_URL%/manifest.json" /><!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See [https://developers.google.com/web/fundamentals/web-app-manifest/](https://developers.google.com/web/fundamentals/web-app-manifest/)
-->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React Address Book App</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
</head><body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
タイトルを変更し、ブートストラップスタイルシートを追加します.今我々は実行してアプリケーションを実行することができます
set PORT=3001 && react-scripts start
WindowsまたはPORT=3006 react-scripts start
Linuxで.endを開始するには、まず
json-server
走らせるnpm i json-server
. プロジェクトフォルダに移動して実行します.json-server --watch db.json
インdb.json
, テキストを次のように変更します.{
"contacts": [
]
}
だから我々はcontacts
で定義されたエンドポイントrequests.js
利用可能です.Reference
この問題について(反応アプリにGoogleマップを加えてください), 我々は、より多くの情報をここで見つけました https://dev.to/aumayeung/add-google-maps-to-a-react-app-4jm6テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol