ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Rust로 SPA 만들기 - 2. 카트에 물건 담기
    SPA 2021. 7. 4. 11:34

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

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

    • 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
Designed by Tistory.