# [React x Django] Fetching Data (Axios) 用途:處理 Fetch的相關 AJAX 事情 1. 進到frontend資料夾 安裝```npm install axios``` 2. Import ```javascript= import React, {useState, useEffect} from 'react' import axios from 'axios' ``` 移除 ```javascript= import products from '../products' ``` > useState, useEffect 解說: > useState只是一個函式,它會接收一作為初始值的參數並回傳一個包含兩個值的array,第一個值是state、第二個值是用來對剛那個state做setState的函式。 > 變數型態 [state變數名稱, setState函式名稱] = useState(state變數初始值) > ```javascript= > const [products, setProducts] = useState([]) > ``` > products 是變數名稱,setProducts 是函式名稱,[] 為初始空Array > products : this.state.products > setProducts:(值)=>{this.setProducts({products:值})} > > ---- >useEffect >資料 fetch、設定 subscription、或手動改變 React component 中的 DOM 都是 side effect >useEffect 視為 componentDidMount,componentDidUpdate 和 componentWillUnmount 的組合 >useEffect 有什麼作用? 透過使用這個 Hook,你告訴 React 你的 component 需要在 render 後做一些事情。React 將記住你傳遞的 function(我們將其稱為「effect」),並在執行 DOM 更新之後呼叫它。 在這個 effect 中,我們設定了網頁的標題,但我們也可以執行資料提取或呼叫其他命令式 API。 >我們宣告 ```products``` state 變數,然後告訴 React 我們需要使用一個 effect。我們將一個 function 傳入給 useEffect Hook。我們傳入的這個 function 就是我們的 effect。在 effect 內部,我們使用fetchProducts。我們可以讀取 effect 中最新的 data,因為它在我們 function 的範圍內。當 React render 我們的 component 時,它會記住我們使用的 effect,然後在更新 DOM 後執行我們的 effect。每次 render 都是這樣,包括第一次。 3. 使用 ```javascript= function HomeScreen() { const [products, setProducts] = useState([]) useEffect(() =>{ async function fetchProducts(){ const { data } = await axios.get('http://127.0.0.1:8000/api/products/') setProducts(data) } fetchProducts() },[]) return ( <div> <h1>最新行程</h1> <Row> {products.map(product => ( <Col key={product._id} sm={12} md={6} lg={4} xl={3}> <Product product={product} /> </Col> ))} </Row> </div> ) } ``` 遇到CORS問題 > https://pypi.org/project/django-cors-headers/ 1. ```backend``` 安裝 ```pip install django-cors-headers``` 2. 安裝完成後,settings.py中配置 ```python= INSTALLED_APPS = [ ... 'corsheaders', ... ] MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', ... ] ``` settings.py底端加上 ```python= CORS_ALLOW_ALL_ORIGINS = True ``` ## 改良成預設網址 ```HomeScreen.js``` ```javascript= useEffect(() =>{ async function fetchProducts(){ const { data } = await axios.get('api/products/') setProducts(data) } fetchProducts() },[]) ``` ```package.json``` ```json= "name": "frontend", "proxy": "http://127.0.0.1:8000", ``` 改好後重啟react ```npm start``` 順利使用! 調整```ProductScreen.js``` tips: ```javascript= axios.get(`/api/products/${match.params.id}`) ``` 記得要用``` ` ``` 而不是```'``` ```javascript= import React, {useState, useEffect} from 'react' import axios from 'axios' import React, {useState, useEffect} from 'react' import { Link } from 'react-router-dom' import { Row, Col, Image, ListGroup, Button, Card, ListGroupItem } from 'react-bootstrap' import Rating from '../components/Rating' import axios from 'axios' function ProductScreen({ match }) { const [product, setProduct] = useState([]) useEffect(() =>{ async function fetchProduct(){ const { data } = await axios.get(`/api/products/${match.params.id}`) setProduct(data) } fetchProduct() },[]) return ( <div> <Link to='/' className='btn btn-light my-3'>Go Back</Link> <Row> <Col md={6}> <Image src={product.image} alt={product.name} fluid /> </Col> <Col md={3}> <ListGroup variant="flush"> <ListGroup.Item> <h3>{product.name}</h3> </ListGroup.Item> <ListGroup.Item> <Rating value={product.rating} text={`人氣 ${product.numReviews}`} color={'#f8e825'}/> </ListGroup.Item> <ListGroup.Item> 價格:${product.price} </ListGroup.Item> <ListGroup.Item> 描述:{product.description} </ListGroup.Item> </ListGroup> </Col> <Col md={3}> <Card> <ListGroup variant='flush'> <ListGroup.Item> <Row> <Col>價格</Col> <Col> <strong>${product.price}</strong> </Col> </Row> </ListGroup.Item> <ListGroup.Item> <Row> <Col>狀態</Col> <Col> {product.countInStock > 0 ? '尚有名額':'目前額滿'} </Col> </Row> </ListGroup.Item> <ListGroup.Item> <Button className='btn-block' disabled={product.countInStock == 0} type='button'> 加入購物車</Button> </ListGroup.Item> </ListGroup> </Card> </Col> </Row> </div> ) } export default ProductScreen ```