본문 바로가기
SPA

Rust로 SPA 만들기 - 2. 카트에 물건 담기

by F.E.D 2021. 7. 4.

아래의 예제는 출처에 포함된 내용을 번역 한 것입니다.

이번에는 카트에 물건을 추가하는 기능을 만들어 보도록 하겠습니다.

  • cart_products라는 새로운 상태 필드에서 장바구니에 추가 된 모든 제품을 추적합니다.
  • 카트에 담기라는 버튼을 만들어서 각 product에 렌더링해주도록 하겠습니다.
  • cart_products라는 버튼을 클릭하면 state로직을 업데이트 해주도록 하겠습니다.

home.rs 파일을 다음과 같이 수정합니다.

// src/pages/home.rs
use yew::prelude::*;

#[derive(Clone)]
struct Product {
    id: i32,
    name: String,
    description: String,
    image: String,
    price: f64
}

struct CartProduct {
    product: Product,
    quantity: i32
}

struct State {
    products: Vec<Product>,
    cart_products: Vec<CartProduct>
}

pub struct Home {
    state: State,
    link: ComponentLink<Self>,
}

pub enum Msg {
    AddToCart(i32),
}

impl Component for Home {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {

        let products: Vec<Product> = vec![
            Product {
                id: 1,
                name: "Yeongmin".to_string(),
                description: "Yegonmin is smilar to irang".to_string(),
                image: "/products/apple.png".to_string(),
                price: 3.65,
            },
            Product {
                id: 2,
                name: "Irang".to_string(),
                description: "Irang is smilar to yeongmin".to_string(),
                image: "/products/banana.png".to_string(),
                price: 7.99,
            }
        ];
        let cart_products = vec![];

        Self {
            state: State {
                products,
                cart_products
            },
            link,
        }
    }

    fn update(&mut self, message: Self::Message) -> ShouldRender {
        match message {
            Msg::AddToCart(product_id) => {
                let product = self
                    .state
                    .products
                    .iter()
                    .find(|p: &&Product| p.id == product_id)
                    .unwrap();
                let cart_product = self
                    .state
                    .cart_products
                    .iter_mut()
                    .find(|cp: &&mut CartProduct| cp.product.id == product_id);

                if let Some(cp) = cart_product {
                    cp.quantity += 1;
                } else {
                    self.state.cart_products.push(CartProduct {
                        product: product.clone(),
                        quantity: 1,
                    })
                }
                true
            }
        }
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        true
    }

    fn view(&self) -> Html {
        let products: Vec<Html> = self
            .state
            .products
            .iter()
            .map(|product: &Product| {
                let product_id = product.id;
                html! {
                    <div>
                        <img src={&product.image} />
                        <div>{&product.name}</div>
                        <div>{"$"}{&product.price}</div>
                        <button onclick=self.link.callback(move |_| Msg::AddToCart(product_id))>{"카트에 담기"}</button>
                    </div>
                }
            })
            .collect();

        let cart_value = self
            .state
            .cart_products
            .iter()
            .fold(0.0, |acc, cp| acc + (cp.quantity as f64 * cp.product.price));

        html! {
            <div>
                <span>{format!("카트값: {:.2}", cart_value)}</span>
                <span>{products}</span>
            </div>
        }
    }
}
  • clone - 사용자가 장바구니에 추가할 때마다 복제된 제품을 CartProduct에 저장할 수 있록 Product struct에서 Clone 특성을 추출했습니다.
  • update - 이 메서드는 컴포넌트의 상태를 업데이트하거나 request 요청과같은 부수작용을 담당하는 로직이 포함되어있습니다. 컴포넌트가 지원하는 모든 작업을 포함하는 enum을 사용하여 호출됩니다. 이 메서드가 true를 반환하면 컴포넌트가 다시 렌더링됩니다.
  • link - 업데이트 생명주기 메서드를 트리거할 수 있는 콜백을 등록할 수 있습니다.

이 컴포넌트는 아래와 같이 동작합니다. 리덕스의 store에 디스패치하는 개념과 비슷하다고 보면 됩니다. 

link는 dispatch와 유사하고 message는 액션과 유사합니다. 

이제 빌드를 하고 다시 serve를 띄워서 카트에 담기 버튼을 클릭해보세요.

위와 같이 카트값이 잘 변하나요?

리액트나 여타 다른 자바스크립트 프레임워크와 달리 러스트로 웹어셈블리 코드에 접근하는 것은 조금 더 네이티브한 성능 이익을 볼 수 있습니다. 

다음 시간에는 데이터를 직접 패치 데이터로 가져오는 것을 해보도록 하겠습니다.

 

감사합니다.

 

 

출처 : http://www.sheshbabu.com/posts/rust-wasm-yew-single-page-application/

 

'SPA' 카테고리의 다른 글

Rust로 SPA 만들기 - 1. 리스트 만들기  (0) 2021.07.03

댓글