iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
Modern Web

跳脫MVC,Laravel + React 建立電商網站系列 第 20

Day 20 Laravel + React 實戰之路 -5(商品列表)

  • 分享至 

  • xImage
  •  

終於進展到2/3的進度了,還是要朝著專案進度繼續邁進。
昨天已經把一些假資料塞到資料庫裡面了,今天就來實作商品列表(首頁)吧!

首先要到web.php 的地方去註冊一個路由,如果是架構很大的情況下建議用檔案來區分不同的路由,避免web.php越長越肥大,但我這邊就便宜行事(我就爛),反正後面也不會維護他XD

關於路由的一些概念,剛好這次鐵人賽有其他大大做了詳細的說明,我就不多贅述。

web.php
我們創建一個home的get router,我這裡把兩種方式都寫出來,都是可行的、結果也一樣,可以依據個人喜好選擇:

Route::get('home' , [\App\Http\Controllers\HomeController::class,'index'])->name('home'); 
Route::get('home' , ['uses'=>'\App\Http\Controllers\HomeController@index' , 'as' => 'home']);

注意:一定要命名、一定要命名、一定要命名(這是良好的開發習慣)

接下來我們要在Http\Controllers底下創立一個HomeController(控制器)
HomeController.php
程式碼很單純的先長這樣。

<?php 
namespace App\Http\Controllers; 
class homeController extends Controller 
{ 
    public function index() 
    { 
        dd(123); 
    } 
     
}

我們可以到網址列輸入 ip + /home,就可以看到一個黑底123的畫面

到目前為止,我們確認了可以順利地從web到指定的controller 去執行指定的function
但我想要限制Controller"不能直接"去存取Model,原因是:我希望Controller只處理請求的邏輯,而不負責拿資料,因此在Controller 跟 Model之間,我想加入一個Service來幫助我們達到目的,Service負責業務邏輯。(這只是一個開發習慣,團隊大家約定並設計好都可以溝通,並沒有一定的對與錯,如果要再細分 還可以再拆repository出來)

project\React\src\Services\ProductService

<?php 
namespace React\Services;
class ProductService 
{

     
}

HomeController 修改
記得要 use Inertia\Inertia;

class HomeController extends Controller 
{ 
    public function __construct(ProductService $product_service) 
    { 
        $this->product_service = $product_service; 
    } 
    public function index() 
    { 
        $all_product = $this->product_service->getProduct(); 
        return Inertia::render('Home', [ 
            'product' => $all_product, 
        ]); 
    } 
}

接下來到存放jsx的地方 新增Home.jsxresources/js/Pages/Home.jsx
建立基本的架構,我們在Controller 要丟給 React 的資料,會用props的方式傳送,所以在這邊要接收product

import react from "react"; 
export default function Home({ product }){ 
    console.log(product); 
    return( 
        <div> 
        </div> 
    ); 
}

根據 用 React思考這篇 官方文章,我們在菜鳥時期最好是先建立靜態畫面,不要想東想西。
所以我這邊想要把每個商品的畫面先固定好
所以到 resources/js/Components 的地方來創建 一個 ProductList Components

import React from 'react'; 
export default function ProductList({title , price , description , image , created_at}){ 
    return ( 
        <div> 
        </div> 
    ); 
}

到這邊發現說:當我們要建立商品的獨立components的時候,會需要一些關聯表的內容(image、price)
這時候就要回去修改一下後端的資料,在Product Model的地方把另外兩章表的關聯設定好,以便後續我們使用預載入的功能。
(前面好像忘記建 price跟image的 Model,這裡就請自行建立吧~)
Product (Model)
Product跟price、image的關係 是 一對多,所以我設定hasMany的關聯

class Product extends BaseModel 
{ 
    use HasFactory; 
    protected $table = 'products'; 
    protected $guarded = []; 
    public function images() 
    { 
        return $this->hasMany(Image::class); 
    } 
    public function prices() 
    { 
        return $this->hasMany(Price::class); 
    } 
}

然後在ProductService 新增一個function

   public function productRelation() 
    { 
        return Product::with('prices' , 'images'); 
    }

然後Controller 改叫這個function

$all_product = $this->product_service->productRelation()->get();

接下來我們把資料dd出來看一下,可以發現關聯表的內容會被放在relation之中

https://ithelp.ithome.com.tw/upload/images/20220924/20145703QHizujv1Qa.png

我們回到畫面上,我們要把Product的畫面做出來,我們發現 在上面的這個結構並不好在js之中取的image跟price,不過沒關係,我們先塞假的東西進去看畫面
home.jsx

return( 
        <div> 
            { 
                product.map( value => { 
                    return <ProductList title={value.name} price={1000} description={value.description} image={"https://pic.616pic.com/ys_img/00/44/76/yYdFMozXJd.jpg"} /> 
                }) 
            } 
        </div> 
    );

(先謝謝圖片提供者)

ProductList.jsx

export default function ProductList({title , price , description , image}){ 
    return ( 
        <div style={{display: "flex" , flexDirection: "column",}}> 
            <div style={{width: "100%"}}> 
                <img src={image} alt={"商品圖片"} /> 
            </div> 
            <div style={{width: "100%"}}> 
                <p>{title}</p> 
                <p style={{color:"red" ,fontWeight:"bolder"}}>{price}</p> 
                <p>{description}</p> 
            </div> 
        </div> 
    ); 
}

PS.接下來為了加快開發速度,會用前端套件的語法來使用,下載下來的breeze是使用tailwind(如果沒誤會的話),剛好過去都沒有使用過tailwind,都是使用boostrap,可以趁這次機會順便練習看看tailwind~

另外,如果要用 bootstrap語法跟一般常用的有所不同,相關語法參考

https://ithelp.ithome.com.tw/upload/images/20220924/201457031xzTgk4dyW.png

我們現在畫面長這樣,但我希望他是橫的排序,因此要修改一下css

home.jsx

export default function Home({product}){
    return(
        <div>
            <div className="flex flex-wrap">
                {
                    product.map( value => {
                        return <ProductList key={value.name} title={value.name} price={1000} description={value.description} image={"https://pic.616pic.com/ys_img/00/44/76/yYdFMozXJd.jpg"} />
                    })
                }
            </div>
        </div>
    );
}

https://ithelp.ithome.com.tw/upload/images/20220924/20145703rsZBQgzlb5.png

我們現在是使用塞假資料的方式讓畫面可以正常運行,明天先稍微修改一下Controller 傳到 React 畫面的資料結構,讓JS好取得資料~


上一篇
Day 19 Laravel + React 實戰之路 -4(假資料)
下一篇
Day 21 Laravel + React 實戰之路 -5(商品列表-後端資料修改)
系列文
跳脫MVC,Laravel + React 建立電商網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
zivhsiao
iT邦新手 4 級 ‧ 2023-02-20 15:59:45

請問大大
project\React\src\Services\ProductService 的路徑是在哪裏,是否再 app 的外面,因為有看到您的寫法是 namespace React\Services;
所以想問一下,這個的路徑?謝謝

bennett iT邦新手 3 級 ‧ 2023-02-21 15:38:20 檢舉

project 是我自己創建的資料夾,他的層級跟app相同
當初會創建project的原因是:在這個環境底下可以將不同的用途的service分類好,方便跟不同的系統溝通

架設未來產品資料拆分成 "訂單系統產品資料"、"賣場產品資料"
我就可以在project底下區分成:
project\Order\src\Services\ProductServices
project\React\src\Services\ProductService

以上淺見,供您參考

我要留言

立即登入留言