# react porject
# 問題待討論
1.分頁功能
* 之前上網查到參考的分頁寫法不懂
* 分頁第一頁 active 效果有點不太懂傳參數的方式
2.localStorage 傳參數的部分不懂 ><
>ask:第 148 行為什麼是寫 checkMyList 而不是 setCheckMyList ?
>有點小小的不太瞭解為什麼第 148 行要撈出 index 值!?

3.localStorage bug >Z 說不是 bug,user 不會從 localStorage 將資料刪除
我發現直接將 localStorage 的資料刪除, UI 不會更新,要重新整理才會更新

4.localStorage UI bug
照著之前那版修改,有的時候畫面還是會出現 紫色奇怪的樣式,後來回去看紫色樣式好像代表沒加入我的最愛加成功

5.function 寫法不同
-方法1
```=js
// import React,{useState, useEffect} from "react";
import CardList from './CardList';
const CardsContent = () =>{
return (
<div className="main">
<h2 className="title-main">請先選擇區域</h2>
<ul className="list">
<CardList/>
<CardList/>
<CardList/>
<CardList/>
<CardList/>
<CardList/>
</ul>
</div>
);
};
export default CardsContent;
```
-方法2
```=js
import React from "react";
function Header() {
return (
<div className="main">
<h2 className="title-main">這是首頁</h2>
</div>
);
}
export default Header;
```
6.不太懂有的時候結構賦值到底要等於什麼,例如:在這邊 App.js 第 112 行為什麼要等於 state?

7.Api 撈回來的資料 讓 每個卡片高度不一樣

8.傳變數問題 (Router)
/
others:
>think:
>一開始 build 專案環境是否就要先直接拆 layout.header.footer.content (頁面內容)出來?還是先寫好功能在拆?
>
Shenny 專案進度回報: https://hackmd.io/h_0GyLXBQ7uXCIIj8D0M0g?both
Shenny 筆記 : https://hackmd.io/xG1tw_nER7Wu3xL1gbGYPQ?both
Shenny React-router:https://hackmd.io/RA8jaPzCToaf9MLaFSGdmA
---
# 將我的最愛景點存入 localstorge
## Card.js
```=Js
import React,{useState,useEffect} from "react";
import clock from '../images/icons_clock.png'
import pin from '../images/icons_pin.png'
import phone from '../images/icons_phone.png'
import tag from '../images/icons_tag.png'
const Card = (props) => {
//isFavorite = true > add favorite already
//isFavorite = false > haven't added in favorite list
const [isFavorite,setIsFavorite] = useState(false);//based localstorage
useEffect(()=>{
if(localStorage.getItem('myFavoirite')!== null){
console.log('id',props.item.Id)
let myFavoirite = JSON.parse(localStorage.getItem('myFavoirite'));
let index = myFavoirite.indexOf(props.item.Id);
console.log('index',index)
if(index >=0)
setIsFavorite(!isFavorite);
console.log('isFavorite',isFavorite)
}
},[]);
const onLikeClick=(e) =>{
e.preventDefault()
//1. check isFavorite
if (isFavorite === false)
{
//2. change style
//style
e.target.textContent="favorite"
//control data
// console.log('id', e.target.parentNode.parentNode.parentNode.id)
let currentId = e.target.parentNode.parentNode.parentNode.id;
if(localStorage.getItem('myFavoirite')!== null){
let myFavoirite = JSON.parse(localStorage.getItem('myFavoirite'));
if(currentId !=='')
myFavoirite.push(currentId);
localStorage.setItem('myFavoirite',JSON.stringify(myFavoirite));
}else{
let myFavoirite = [];
if(currentId !=='')
myFavoirite.push(currentId);
localStorage.setItem('myFavoirite',JSON.stringify(myFavoirite));
}
}
else{
//style
e.target.textContent="favorite-border"
//control data
// console.log('id', e.target.parentNode.parentNode.parentNode.id)
let currentId = e.target.parentNode.parentNode.parentNode.id;
if(localStorage.getItem('myFavoirite')!== null){
let myFavoirite = JSON.parse(localStorage.getItem('myFavoirite'));
if(currentId !==''){
let index = myFavoirite.indexOf(currentId);
myFavoirite.splice(index,1);
}
localStorage.setItem('myFavoirite',JSON.stringify(myFavoirite));
}else{
alert('程式有誤請聯絡管理員');
}
}
//3. udate isFavorite
setIsFavorite(!isFavorite);
}
const {item} = props;
return(
<li className="list-card" id={item.Id}>
<div className="img" style={{backgroundImage: `url(${item.Picture1})`}}>
<a className="material-icons" onClick={onLikeClick} href="!#"><i>favorite_border</i>
</a>
<div className="img-title">
<h3 className="title-24px">{item.Name}</h3>
<p className="title-16px">{item.Zone}</p>
</div>
</div>
<div className="content-card">
{/* <a onClick={onLikeClick} href="#"><span className="circle"><i className="material-icons color like">favorite_border</i></span></a> */}
<p><img src={clock} alt="icon"/>{item.Opentime}</p>
<p><img src={pin} alt="icon"/>{item.Add}</p>
<div className="card_down_area">
<p><img src={phone} alt="icon"/>{item.Tel}</p>
<p><img src={tag} alt="icon"/>{item.Ticketinfo}</p>
</div>
</div>
</li>
)
};
export default Card;
```
# 如何在return 在map裡面去做判斷
這個範例是印出每個景點的名字,不是今天改得物件
你要參考要記得不要照抄
```=Js
{cards.map(function(card,index) {
//取出index索引小於5的資料
if(index < 5)
return <ul className="list">{card.Name}</ul>
else
return null
//或是使用三元表示式
//return index < 5 ? <ul className="list">{card.Name}</ul>: null
})}
```
# 使用props傳入物件至組建
### App.js
```=js
import './css/App.css';
import gotopIcon from './images/btn_goTop.png'
import List from './components/List';
import Dropdown from './components/Dropdown';
import Card from './components/Card';
import React, { useState,useEffect } from 'react';
const App = () => {
const [state,setState] = useState({
items: [],
error: null,
isLoaded: false,
itemZones:[]
});
//api
useEffect(()=>{
fetch( 'https://raw.githubusercontent.com/hexschool/KCGTravel/master/datastore_search.json',{method:"GET"})
.then(res => res.json())
.then(
(data) => {
setState({
isLoaded: true,
items: data.result.records,
itemZones: data.result.records.map((item)=>(item.Zone)).filter(function(element, index, arr){
return arr.indexOf(element) === index;
})
});
},
(sError) => {
setState({
isLoaded: true,
error:sError
});
}
)
},[]);
return (
<div className="App">
<header className="banner">
<div className="container">
<h1>高雄旅遊資訊網</h1>
<Dropdown itemZones= {state.itemZones}/>
<div className="menu">
<p className="title-menu">熱門行政區</p>
<List/>
</div>
<div className="icon-menu">
<hr />
</div>
</div>
</header>
<div className="content container">
<div className="main">
<h2>請先選擇區域</h2>
<Card items={state.items}/>
</div>
<div className="goTop">
<img src={gotopIcon} alt="gotopIcon"/>
</div>
{/* <Pagination/> */}
{/* <ul className="page">
<li><a href="https://hackmd.io/xG1tw_nER7Wu3xL1gbGYPQ?both">Prev </a></li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">Next</a></li>
</ul> */}
</div>
<footer>
<div className="container">
<p>高雄旅遊網</p>
<p className="pStyle">資料來源: 高雄市政府</p>
</div>
</footer>
</div>
);
}
export default App;
```
### dropdownlist.js
```=js
import React from 'react';
const Dropdown = (props) =>{
let {itemZones} = props;
return (
<div>
<select>
<option selected disabled>--請選擇行政區--</option>
{itemZones.map((zone) =>(
<option value={zone}>{zone}</option>
)
)}
</select>
</div>
);
}
export default Dropdown;
```
### Card.js(先是示範只秀name)
```=js
import React, {} from 'react';
const Card = (props) =>{
let {items} = props;
return(
<div> {items.map((item) =>(
<p>{item.Name}</p>
)
)}</div>
)
}
export default Card;
```
---
(下面是舊的略過...)
## hooks
```=js
// import React,{Component} from "react";
import React,{useState, useEffect} from "react";
const API = () =>{
const [state,setState] = useState({
items: [],
error: null,
isLoaded: false
});
useEffect(()=>{
fetch( 'https://raw.githubusercontent.com/hexschool/KCGTravel/master/datastore_search.json',{method:"GET"})
.then(res => res.json())
.then(
(data) => {
setState({
isLoaded: true,
items: data.result.records
});
},
(sError) => {
setState({
isLoaded: true,
error:sError,
items:null
});
}
)
},[]);
const { error, isLoaded, items } = state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
{items.map(item => (
<p> {item.Name}</p>
))}
</ul>
);
}
}
// class API extends Component{
// constructor(props) {
// super(props);
// this.state = {
// error: null,
// isLoaded: false,
// items: []
// };
// }
// componentDidMount() {
// fetch( 'https://raw.githubusercontent.com/hexschool/KCGTravel/master/datastore_search.json',{method:"GET"})
// .then(res => res.json())
// .then(
// (data) => {
// this.setState({
// isLoaded: true,
// items: data.result.records
// });
// },
// // Note: it's important to handle errors here
// // instead of a catch() block so that we don't swallow
// // exceptions from actual bugs in components.
// (error) => {
// this.setState({
// isLoaded: true,
// error
// });
// }
// )
// }
// render() {
// const { error, isLoaded, items } = this.state;
// if (error) {
// return <div>Error: {error.message}</div>;
// } else if (!isLoaded) {
// return <div>Loading...</div>;
// } else {
// return (
// <ul>
// {items.map(item => (
// <p> {item.Name}</p>
// ))}
// </ul>
// );
// }
// }
// }
export default API;
```
## API
```=react.js
import React,{Component} from "react";
class API extends Component{
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
items: []
};
}
componentDidMount() {
fetch( 'https://raw.githubusercontent.com/hexschool/KCGTravel/master/datastore_search.json',{method:"GET"})
.then(res => res.json())
.then(
(data) => {
this.setState({
isLoaded: true,
items: data.result.records
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
{items.map(item => (
<p> {item.Name}</p>
))}
</ul>
);
}
}
}
export default API;
```
## APP
```=react.js
import logo from './logo.svg';
import './App.css';
// import List from './List';
//API
import API from './testAPI';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
<API/>
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
```