# react porject # 問題待討論 1.分頁功能 * 之前上網查到參考的分頁寫法不懂 * 分頁第一頁 active 效果有點不太懂傳參數的方式 2.localStorage 傳參數的部分不懂 >< >ask:第 148 行為什麼是寫 checkMyList 而不是 setCheckMyList ? >有點小小的不太瞭解為什麼第 148 行要撈出 index 值!? ![](https://i.imgur.com/tEI0zMe.png) 3.localStorage bug >Z 說不是 bug,user 不會從 localStorage 將資料刪除 我發現直接將 localStorage 的資料刪除, UI 不會更新,要重新整理才會更新 ![](https://i.imgur.com/zpZvY94.png) 4.localStorage UI bug 照著之前那版修改,有的時候畫面還是會出現 紫色奇怪的樣式,後來回去看紫色樣式好像代表沒加入我的最愛加成功 ![](https://i.imgur.com/0pXWuvU.png) 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? ![](https://i.imgur.com/dlMeUMB.png) 7.Api 撈回來的資料 讓 每個卡片高度不一樣 ![](https://i.imgur.com/IV0eLSE.png) 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; ```