Elm으로 웹 프론트엔드를 안정적으로 만드세요
게시 됨: 2022-03-11웹 프론트 엔드를 디버깅하려고 몇 번이나 복잡한 이벤트 체인을 처리하는 코드에 얽힌 자신을 발견했습니까?
jQuery, Backbone.js 또는 기타 인기 있는 JavaScript 프레임워크로 빌드된 많은 구성 요소를 처리하는 UI용 코드를 리팩터링하려고 시도한 적이 있습니까?
이러한 시나리오에서 가장 고통스러운 점 중 하나는 불확실한 여러 이벤트 시퀀스를 따르고 이러한 모든 동작을 예상하고 수정하는 것입니다. 단순히 악몽!
저는 항상 웹 프론트 엔드 개발의 이 지옥 같은 측면에서 벗어날 방법을 찾았습니다. Backbone.js는 웹 프론트 엔드에 오랫동안 누락된 구조를 제공함으로써 이와 관련하여 잘 작동했습니다. 그러나 가장 사소한 일을 수행하는 데 필요한 장황함을 감안할 때 훨씬 더 나은 것으로 판명되지 않았습니다.
그러다 엘름을 만났다.
Elm은 Haskell 프로그래밍 언어를 기반으로 하는 정적으로 유형이 지정된 기능 언어이지만 사양은 더 간단합니다. 컴파일러(Haskell을 사용하여 빌드됨)는 Elm 코드를 구문 분석하고 JavaScript로 컴파일합니다.
Elm은 원래 프론트 엔드 개발을 위해 제작되었지만 소프트웨어 엔지니어는 서버 측 프로그래밍에도 사용할 수 있는 방법을 찾았습니다.
이 기사는 Elm이 웹 프론트 엔드 개발에 대한 생각을 어떻게 바꿀 수 있는지에 대한 개요와 이 함수형 프로그래밍 언어의 기본에 대한 소개를 제공합니다. 이 튜토리얼에서는 Elm을 사용하여 장바구니와 같은 간단한 애플리케이션을 개발할 것입니다.
왜 느릅나무인가?
Elm은 많은 이점을 약속하며 대부분은 깨끗한 웹 프런트 엔드 아키텍처를 달성하는 데 매우 유용합니다. Elm은 다른 인기 있는 프레임워크(심지어 React.js도 포함)보다 더 나은 HTML 렌더링 성능 이점을 제공합니다. 게다가 Elm은 개발자가 코드를 작성할 수 있게 해주므로 실제로 JavaScript와 같은 동적으로 유형이 지정된 언어를 괴롭히는 대부분의 런타임 예외를 생성하지 않습니다.
컴파일러는 자동으로 유형을 유추하고 친숙한 오류를 내보냅니다. 따라서 개발자는 런타임 전에 잠재적인 문제를 인지할 수 있습니다.
NoRedInk는 36,000개의 Elm 라인을 보유하고 있으며 1년 이상 생산된 후에도 여전히 단일 런타임 예외를 생성하지 않았습니다. [원천]
Elm을 사용해 보기 위해 기존 JavaScript 애플리케이션 전체를 변환할 필요는 없습니다. JavaScript와의 뛰어난 상호 운용성을 통해 기존 응용 프로그램의 일부만 가져와 Elm에서 다시 작성할 수도 있습니다.
Elm은 또한 제공해야 하는 것에 대한 철저한 설명을 제공할 뿐만 아니라 The Elm Architecture에 따라 웹 프론트엔드 구축에 대한 적절한 가이드를 제공하는 훌륭한 문서를 보유하고 있습니다. 이는 모듈성, 코드 재사용 및 테스트에 매우 좋습니다. .
간단한 카트를 만들어보자
Elm 코드의 매우 짧은 스니펫으로 시작하겠습니다.
import List exposing (..) cart = [] item product quantity = { product = product, qty = quantity } product name price = { name = name, price = price } add cart product = if isEmpty (filter (\item -> item.product == product) cart) then append cart [item product 1] else cart subtotal cart = -- we want to calculate cart subtotal sum (map (\item -> item.product.price * toFloat item.qty) cart)
--앞에 오는 모든 텍스트는 Elm의 주석입니다.
여기에서 장바구니를 항목 목록으로 정의하고 있습니다. 여기서 모든 항목은 두 가지 값(해당 제품과 수량)이 있는 레코드입니다. 각 제품은 이름과 가격이 있는 레코드입니다.
장바구니에 제품을 추가하려면 해당 항목이 이미 장바구니에 있는지 확인해야 합니다.
그렇다면 우리는 아무 것도 하지 않습니다. 그렇지 않으면 제품을 장바구니에 새 항목으로 추가합니다. 목록을 필터링하고 각 항목을 제품과 일치시키고 필터링된 결과 목록이 비어 있는지 확인하여 제품이 이미 장바구니에 있는지 확인합니다.
소계를 계산하기 위해 장바구니에 있는 항목을 반복하고 해당 제품 수량과 가격을 찾고 모두 합산합니다.
이것은 카트와 관련 기능이 얻을 수 있는 것처럼 최소한입니다. 우리는 이 코드로 시작하여 이를 단계별로 개선하여 완전한 웹 구성 요소 또는 Elm의 용어로 프로그램을 만들 것입니다.
프로그램의 다양한 식별자에 유형을 추가하는 것으로 시작하겠습니다. Elm은 자체적으로 유형을 유추할 수 있지만 Elm과 해당 컴파일러를 최대한 활용하려면 유형을 명시적으로 표시하는 것이 좋습니다.
module Cart1 exposing ( Cart, Item, Product , add, subtotal , itemSubtotal ) -- This is module and its API definition {-| We build an easy shopping cart. @docs Cart, Item, Product, add, subtotal, itemSubtotal -} import List exposing (..) -- we need list manipulation functions {-| Cart is a list of items. -} type alias Cart = List Item {-| Item is a record of product and quantity. -} type alias Item = { product : Product, qty : Int } {-| Product is a record with name and price -} type alias Product = { name : String, price : Float } {-| We want to add stuff to a cart. This is a function definition, it takes a cart, a product to add and returns new cart -} add : Cart -> Product -> Cart {-| This is an implementation of the 'add' function. Just append product item to the cart if there is no such product in the cart listed. Do nothing if the product exists. -} add cart product = if isEmpty (filter (\item -> item.product == product) cart) then append cart [Item product 1] else cart {-| I need to calculate cart subtotal. The function takes a cart and returns float. -} subtotal : Cart -> Float {-| It's easy -- just sum subtotal of all items. -} subtotal cart = sum (map itemSubtotal cart) {-| Item subtotal takes item and return the subtotal float. -} itemSubtotal : Item -> Float {-| Subtotal is based on product's price and quantity. -} itemSubtotal item = item.product.price * toFloat item.qty유형 주석을 사용하여 컴파일러는 이제 런타임 예외가 발생했을 문제를 포착할 수 있습니다.
그러나 Elm은 여기서 멈추지 않습니다. Elm Architecture는 웹 프론트 엔드를 구성하기 위한 간단한 패턴을 통해 개발자를 안내하며 대부분의 개발자에게 이미 친숙한 개념을 통해 수행됩니다.
- 모델: 모델은 프로그램의 상태를 유지합니다.
- 보기: 보기는 상태를 시각적으로 표현한 것입니다.
- 업데이트: 업데이트는 상태를 변경하는 방법입니다.
업데이트 를 컨트롤러로 처리하는 코드 부분을 생각한다면 좋은 오래된 MVC(Model-View-Controller) 패러다임과 매우 유사한 것을 갖게 됩니다.
Elm은 순수 함수형 프로그래밍 언어이기 때문에 모든 데이터는 변경할 수 없습니다. 즉, 모델을 변경할 수 없습니다. 대신 업데이트 기능을 통해 수행하는 이전 모델을 기반으로 새 모델을 만들 수 있습니다.
왜 그렇게 대단해?
불변 데이터를 사용하면 함수에 더 이상 부작용이 있을 수 없습니다. 이것은 곧 논의할 Elm의 시간 여행 디버거를 포함하여 가능성의 세계를 열어줍니다.
뷰는 모델의 변경이 뷰의 변경을 요구할 때마다 렌더링되며, 순수 함수가 항상 동일한 결과를 반환하는 것과 거의 동일한 방식으로 모델의 동일한 데이터에 대해 항상 동일한 결과를 얻습니다. 동일한 입력 인수.
주요 기능으로 시작
장바구니 애플리케이션에 대한 HTML 보기를 구현해 보겠습니다.
React에 익숙하다면 이것이 감사할 것이라고 확신합니다. Elm에는 HTML 요소를 정의하기 위한 패키지가 있습니다. 이를 통해 외부 템플릿 언어에 의존하지 않고도 Elm을 사용하여 보기를 구현할 수 있습니다.
HTML 요소에 대한 래퍼는 Html 패키지에서 사용할 수 있습니다.
import Html exposing (Html, button, table, caption, thead, tbody, tfoot, tr, td, th, text, section, p, h1)모든 Elm 프로그램은 기본 기능을 실행하여 시작합니다.
type alias Stock = List Product type alias Model = { cart : Cart, stock : Stock } main = Html.beginnerProgram { model = Model [] [ Product "Bicycle" 100.50 , Product "Rocket" 15.36 , Product "Biscuit" 21.15 ] , view = view , update = update }여기서 main 함수는 일부 모델, 보기 및 업데이트 함수로 Elm 프로그램을 초기화합니다. 우리는 몇 가지 종류의 제품과 가격을 정의했습니다. 간단하게 하기 위해 우리는 제품 수가 무제한이라고 가정합니다.
간단한 업데이트 기능
업데이트 기능은 우리의 애플리케이션이 살아나는 곳입니다.
메시지를 받아 메시지 내용에 따라 상태를 업데이트합니다. 두 개의 매개변수(메시지와 현재 모델)를 취하고 새 모델을 반환하는 함수로 정의합니다.
type Msg = Add Product update : Msg -> Model -> Model update msg model = case msg of Add product -> { model | cart = add model.cart product } 현재로서는 메시지가 Add product product 함께 cart 의 add 메소드를 호출합니다.
업데이트 기능은 Elm 프로그램의 복잡성이 증가함에 따라 커질 것입니다.
보기 기능 구현
다음으로 장바구니에 대한 보기를 정의합니다.
보기는 모델을 HTML 표현으로 변환하는 기능입니다. 그러나 정적 HTML만 있는 것은 아닙니다. HTML 생성기는 다양한 사용자 상호 작용 및 이벤트를 기반으로 애플리케이션에 메시지를 다시 내보낼 수 있습니다.
view : Model -> Html Msg view model = section [style [("margin", "10px")]] [ stockView model.stock , cartView model.cart ] stockView : Stock -> Html Msg stockView stock = table [] [ caption [] [ h1 [] [ text "Stock" ] ] , thead [] [ tr [] [ th [align "left", width 100] [ text "Name" ] , th [align "right", width 100] [ text "Price" ] , th [width 100] [] ] ] , tbody [] (map stockProductView stock) ] stockProductView : Product -> Html Msg stockProductView product = tr [] [ td [] [ text product.name ] , td [align "right"] [ text ("\t$" ++ toString product.price) ] , td [] [ button [ onClick (Add product) ] [ text "Add to Cart" ] ] ] Html 패키지는 일반적으로 사용되는 모든 요소에 대한 래퍼를 친숙한 이름의 함수로 제공합니다(예: 함수 section 은 <section> 요소를 생성함).
Html.Attributes 패키지의 일부인 style 함수는 결과 요소에 스타일 특성을 설정하기 위해 section 함수에 전달할 수 있는 개체를 생성합니다.
더 나은 재사용성을 위해 보기를 별도의 기능으로 분할하는 것이 좋습니다.
일을 단순하게 유지하기 위해 뷰 코드에 직접 CSS와 일부 레이아웃 속성을 포함했습니다. 그러나 Elm 코드에서 HTML 요소의 스타일을 지정하는 프로세스를 간소화하는 라이브러리가 있습니다.
스니펫 끝에 있는 button 과 버튼의 클릭 이벤트에 Add product 메시지를 연결한 방법을 확인하세요.
Elm은 콜백 함수를 실제 이벤트와 바인딩하는 데 필요한 모든 코드를 생성하고 관련 매개변수를 사용하여 업데이트 함수를 생성 및 호출하는 작업을 처리합니다.
마지막으로 뷰의 마지막 부분을 구현해야 합니다.
cartView : Cart -> Html Msg cartView cart = if isEmpty cart then p [] [ text "Cart is empty" ] else table [] [ caption [] [ h1 [] [ text "Cart" ]] , thead [] [ tr [] [ th [ align "left", width 100 ] [ text "Name" ] , th [ align "right", width 100 ] [ text "Price" ] , th [ align "center", width 50 ] [ text "Qty" ] , th [ align "right", width 100 ] [ text "Subtotal" ] ] ] , tbody [] (map cartProductView cart) , tfoot [] [ tr [style [("font-weight", "bold")]] [ td [ align "right", colspan 4 ] [ text ("$" ++ toString (subtotal cart)) ] ] ] ] cartProductView : Item -> Html Msg cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align "right" ] [ text ("$" ++ toString item.product.price) ] , td [ align "center" ] [ text (toString item.qty) ] , td [ align "right" ] [ text ("$" ++ toString (itemSubtotal item)) ] ] 여기에서 장바구니의 내용을 렌더링하는 뷰의 다른 부분을 정의했습니다. 보기 함수는 메시지를 내보내지 않지만 보기로 자격을 얻으려면 반환 유형 Html Msg 가 있어야 합니다.
보기는 카트의 내용을 나열할 뿐만 아니라 카트의 내용을 기반으로 소계를 계산하고 렌더링합니다.
이 Elm 프로그램의 전체 코드는 여기에서 찾을 수 있습니다.
지금 Elm 프로그램을 실행하면 다음과 같은 내용이 표시됩니다.
어떻게 작동합니까?
우리 프로그램은 main 기능에서 상당히 비어 있는 상태로 시작합니다. 즉, 몇 가지 하드 코딩된 제품이 있는 빈 카트입니다.
"장바구니에 추가" 버튼을 클릭할 때마다 업데이트 기능에 메시지가 전송되고, 업데이트 기능은 그에 따라 카트를 업데이트하고 새 모델을 생성합니다. 모델이 업데이트될 때마다 HTML 트리를 재생성하기 위해 Elm이 보기 기능을 호출합니다.
Elm은 React와 유사한 Virtual DOM 방식을 사용하기 때문에 UI 변경이 필요할 때만 수행되어 빠른 성능을 보장합니다.
유형 검사기뿐만 아니라
Elm은 정적으로 유형이 지정되지만 컴파일러는 유형 이상의 것을 확인할 수 있습니다.
Msg 유형을 변경하고 컴파일러가 이에 대해 어떻게 반응하는지 살펴보겠습니다.
type Msg = Add Product | ChangeQty Product String장바구니에 담긴 제품의 수량을 변경하는 또 다른 종류의 메시지를 정의했습니다. 그러나 업데이트 함수에서 이 메시지를 처리하지 않고 프로그램을 다시 실행하려고 하면 다음 오류가 발생합니다.

더 기능적인 카트를 향해
이전 섹션에서 수량 값의 유형으로 문자열을 사용했습니다. 이는 값이 문자열 유형이 될 <input> 요소에서 올 것이기 때문입니다.
Cart 모듈에 새로운 함수 changeQty 를 추가해 보겠습니다. 모듈 API를 변경하지 않고 필요할 경우 나중에 변경할 수 있도록 모듈 내부에 구현을 유지하는 것이 항상 더 좋습니다.
{-| Change quantity of the product in the cart. Look at the result of the function. It uses Result type. The Result type has two parameters: for bad and for good result. So the result will be Error "msg" or a Cart with updated product quantity. -} changeQty : Cart -> Product -> Int -> Result String Cart {-| If the quantity parameter is zero the product will be removed completely from the cart. If the quantity parameter is greater then zero the quantity of the product will be updated. Otherwise (qty < 0) the error will be returned. -} changeQty cart product qty = if qty == 0 then Ok (filter (\item -> item.product /= product) cart) else if qty > 0 then Result.Ok (map (\item -> if item.product == product then { item | qty = qty } else item) cart) else Result.Err ("Wrong negative quantity used: " ++ (toString qty)) 우리는 함수가 어떻게 사용될지에 대해 어떤 가정도 해서는 안됩니다. 매개변수 qty 에 Int 가 포함될 것이라고 확신할 수 있지만 값은 무엇이든 될 수 있습니다. 따라서 값을 확인하고 유효하지 않은 경우 오류를 보고합니다.
그에 따라 update 기능도 업데이트합니다.
update msg model = case msg of Add product -> { model | cart = add model.cart product } ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> { model | cart = cart } Err msg -> model -- do nothing, the wrong input Err msg -> model -- do nothing, the wrong quantity 사용하기 전에 메시지의 문자열 quantity 매개변수를 숫자로 변환합니다. 문자열에 잘못된 숫자가 있는 경우 오류로 보고합니다.
여기서 우리는 오류가 발생했을 때 모델을 변경하지 않은 상태로 유지합니다. 또는 사용자가 볼 수 있는 보기의 메시지로 오류를 보고하는 방식으로 모델을 업데이트할 수 있습니다.
type alias Model = { cart : Cart, stock : Stock, error : Maybe String } main = Html.beginnerProgram { model = Model [] -- empty cart [ Product "Bicycle" 100.50 -- stock , Product "Rocket" 15.36 , Product "Bisquit" 21.15 ] Nothing -- error (no error at beginning) , view = view , update = update } update msg model = case msg of Add product -> { model | cart = add model.cart product } ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> { model | cart = cart, error = Nothing } Err msg -> { model | error = Just msg } Err msg -> { model | error = Just msg } 우리는 모델의 error 속성에 대해 Maybe String 유형을 사용합니다. 아마도 Nothing 또는 특정 유형의 값을 보유할 수 있는 또 다른 유형입니다.
다음과 같이 보기 기능을 업데이트한 후:
view model = section [style [("margin", "10px")]] [ stockView model.stock , cartView model.cart , errorView model.error ] errorView : Maybe String -> Html Msg errorView error = case error of Just msg -> p [style [("color", "red")]] [ text msg ] Nothing -> p [] []다음 내용이 표시되어야 합니다.
숫자가 아닌 값(예: "1a")을 입력하려고 하면 위의 스크린샷과 같은 오류 메시지가 표시됩니다.
패키지의 세계
Elm에는 자체 오픈 소스 패키지 저장소가 있습니다. Elm용 패키지 관리자를 사용하면 이 패키지 풀을 쉽게 활용할 수 있습니다. 리포지토리의 크기는 Python 또는 PHP와 같은 다른 성숙한 프로그래밍 언어와 비교할 수 없지만 Elm 커뮤니티는 매일 더 많은 패키지를 구현하기 위해 열심히 노력하고 있습니다.
우리가 보기에 가격의 소수점 이하 자릿수가 어떻게 일치하지 않는지 알 수 있습니까?
toString 의 순진한 사용을 저장소의 더 나은 것으로 교체해 보겠습니다.
cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align "right" ] [ text (formatPrice item.product.price) ] , td [ align "center" ] [ input [ value (toString item.qty) , onInput (ChangeQty item.product) , size 3 --, type' "number" ] [] ] , td [ align "right" ] [ text (formatPrice (itemSubtotal item)) ] ] formatPrice : Float -> String formatPrice price = format "$0,0.00" price 여기서는 숫자 패키지의 format 기능을 사용하고 있습니다. 이것은 우리가 일반적으로 통화 형식을 지정하는 방식으로 숫자 형식을 지정합니다.
100.5 -> $100.50 15.36 -> $15.36 21.15 -> $21.15자동 문서 생성
Elm 리포지토리에 패키지를 게시할 때 코드의 주석을 기반으로 문서가 자동으로 생성됩니다. 여기에서 장바구니 모듈에 대한 문서를 확인하면 실제로 작동하는 것을 볼 수 있습니다. 이 모든 것은 Cart.elm 파일에 있는 주석에서 생성되었습니다.
프론트엔드를 위한 진정한 디버거
가장 명백한 문제는 컴파일러 자체에서 감지하고 보고합니다. 그러나 논리적 오류로부터 안전한 응용 프로그램은 없습니다.
Elm의 모든 데이터는 변경할 수 없으며 모든 것이 업데이트 함수에 전달된 메시지를 통해 발생하므로 Elm 프로그램의 전체 흐름은 일련의 모델 변경으로 나타낼 수 있습니다. 디버거에게 Elm은 턴제 전략 게임과 같습니다. 이를 통해 디버거는 시간 여행과 같은 정말 놀라운 기능을 수행할 수 있습니다. 프로그램의 수명 동안 발생한 다양한 모델 변경 사이를 점프하여 프로그램의 흐름을 앞뒤로 이동할 수 있습니다.
여기에서 디버거에 대해 자세히 알아볼 수 있습니다.
백엔드와 상호 작용
그래서 우리는 좋은 장난감을 만들었는데 느릅나무를 진지한 데 사용할 수 있습니까? 전적으로.
장바구니 프론트엔드를 비동기 백엔드와 연결해 보겠습니다. 그것을 흥미롭게 만들기 위해 우리는 특별한 것을 구현할 것입니다. 모든 카트와 그 내용물을 실시간으로 검사하고 싶다고 가정해 봅시다. 실생활에서 우리는 이 접근 방식을 사용하여 온라인 상점이나 시장에 추가적인 마케팅/판매 기능을 제공하거나 사용자에게 몇 가지 제안을 하거나 필요한 재고 자원 등을 추정할 수 있습니다.
그래서 우리는 클라이언트 측에 카트를 저장하고 서버에 실시간으로 각 카트에 대해 알립니다.
일을 단순하게 유지하기 위해 Python을 사용하여 백엔드를 구현합니다. 백엔드에 대한 전체 코드는 여기에서 찾을 수 있습니다.
WebSocket을 사용하고 메모리 내 카트의 내용을 추적하는 간단한 웹 서버입니다. 일을 단순하게 유지하기 위해 다른 모든 사람의 장바구니를 같은 페이지에 렌더링합니다. 이것은 별도의 페이지 또는 별도의 Elm 프로그램으로 쉽게 구현할 수 있습니다. 지금은 모든 사용자가 다른 사용자의 장바구니 요약을 볼 수 있습니다.
백엔드가 준비되면 이제 Elm 앱을 업데이트하여 카트 업데이트를 서버로 보내고 받아야 합니다. 우리는 JSON을 사용하여 Elm이 훌륭하게 지원하는 페이로드를 인코딩할 것입니다.
CartEncoder.elm
Elm 데이터 모델을 JSON 문자열 표현으로 변환하는 인코더를 구현합니다. 이를 위해 Json.Encode 라이브러리를 사용해야 합니다.
module CartEncoder exposing (cart) import Cart2 exposing (Cart, Item, Product) import List exposing (map) import Json.Encode exposing (..) product : Product -> Value product product = object [ ("name", string product.name) , ("price", float product.price) ] item : Item -> Value item item = object [ ("product", product item.product) , ("qty", int item.qty) ] cart : Cart -> Value cart cart = list (map item cart) 라이브러리는 Elm 객체를 가져와 JSON 인코딩 문자열로 바꾸는 일부 함수(예: string , int , float , object 등)를 제공합니다.
CartDecoder.elm
모든 Elm 데이터에 유형이 있고 어떤 JSON 값을 어떤 유형으로 변환해야 하는지 정의해야 하므로 디코더를 구현하는 것은 조금 더 까다롭습니다.
module CartDecoder exposing (cart) import Cart2 exposing (Cart, Item, Product) -- decoding for Cart import Json.Decode exposing (..) -- will decode cart from string cart : Decoder (Cart) cart = list item -- decoder for cart is a list of items item : Decoder (Item) item = object2 Item -- decoder for item is an object with two properties: ("product" := product) -- 1) "product" of product ("qty" := int) -- 2) "qty" of int product : Decoder (Product) product = object2 Product -- decoder for product also an object with two properties: ("name" := string) -- 1) "name" ("price" := float) -- 2) "price"업데이트된 느릅나무 응용 프로그램
최종 Elm 코드가 조금 더 길기 때문에 여기에서 찾을 수 있습니다. 다음은 프런트 엔드 애플리케이션의 변경 사항을 요약한 것입니다.
장바구니가 업데이트될 때마다 장바구니 내용의 변경 사항을 백엔드로 보내는 기능으로 원래 update 기능을 래핑했습니다.
updateOnServer msg model = let (newModel, have_to_send) = update msg model in case have_to_send of True -> -- send updated cart to server (!) newModel [ WebSocket.send server (encode 0 (CartEncoder.cart newModel.cart)) ] False -> -- do nothing (newModel, Cmd.none) 또한 서버에서 업데이트를 수신하고 그에 따라 로컬 모델을 업데이트하기 위해 ConsumerCarts String 의 추가 메시지 유형을 추가했습니다.
consumersCartsView 기능을 사용하여 다른 사람의 장바구니 요약을 렌더링하도록 보기가 업데이트되었습니다.
다른 사람의 장바구니에 대한 변경 사항을 수신 대기하기 위해 백엔드를 구독하기 위해 WebSocket 연결이 설정되었습니다.
subscriptions : Model -> Sub Msg subscriptions model = WebSocket.listen server ConsumerCarts server = "ws://127.0.0.1:8765" 주요 기능도 업데이트했습니다. 이제 추가 init 및 subscriptions 매개변수와 함께 Html.program 을 사용합니다. init 는 프로그램의 초기 모델을 지정하고 subscription 은 구독 목록을 지정합니다.
구독은 특정 채널의 변경 사항을 수신 대기하고 해당 메시지를 update 기능으로 전달하도록 Elm에 지시하는 방법입니다.
main = Html.program { init = init , view = view , update = updateOnServer , subscriptions = subscriptions } init = ( Model [] -- empty cart [ Product "Bicycle" 100.50 -- stock , Product "Rocket" 15.36 , Product "Bisquit" 21.15 ] Nothing -- error (no error at beginning) [] -- consumer carts list is empty , Cmd.none)마지막으로 서버에서 수신한 ConsumerCart 메시지를 디코딩하는 방법을 처리했습니다. 이렇게 하면 외부 소스에서 받은 데이터가 응용 프로그램을 손상시키지 않습니다.
ConsumerCarts message -> case decodeString (Json.Decode.list CartDecoder.cart) message of Ok carts -> ({ model | consumer_carts = carts }, False) Err msg -> ({ model | error = Just msg, consumer_carts = [] }, False)프론트 엔드를 정상 상태로 유지
느릅나무는 다릅니다. 개발자가 다르게 생각해야 합니다.
JavaScript 및 이와 유사한 언어 영역에서 온 사람이라면 누구나 Elm의 작업 방식을 배우려고 할 것입니다.
하지만 궁극적으로 Elm은 다른 프레임워크(가장 인기 있는 프레임워크조차도)가 종종 하기 힘든 것을 제공합니다. 즉, 방대한 장황한 코드에 얽매이지 않고 강력한 프론트 엔드 애플리케이션을 구축할 수 있는 수단을 제공합니다.
Elm은 또한 스마트 컴파일러와 강력한 디버거를 결합하여 JavaScript가 제기하는 많은 어려움을 추상화합니다.
Elm은 프론트엔드 개발자들이 오랫동안 갈망해 온 것입니다. 이제 실제로 작동하는 것을 보았으므로 직접 사용해 보고 Elm에서 다음 웹 프로젝트를 빌드하여 이점을 얻으십시오.
