首页 > 解决方案 > 模型属性改变时调用组件方法

问题描述

在我的带有 Elmish 的 Fable 应用程序中,我有一个使用react- slick 的视图和一个应该能够在单击时更改幻灯片编号的按钮:

Fable.Import.Slick.slider
  [ InitialSlide model.SlideNumber
    AfterChange (SlideTo >> dispatch) ]
  children

Button.button
  [ Button.OnClick (fun _ev -> dispatch (SlideTo 5)) ]
  [ str "Go to slide 5" ]

滑块的反应组件由 定义react-slick
我必须自己编写的寓言包装器,所以它不完整,因为我只定义了我需要的属性。

module Fable.Import.Slick

open Fable.Core
open Fable.Core.JsInterop
open Fable.Helpers
open Fable.Helpers.React.Props
open Fable.Import.React

type SliderProps =
    | InitialSlide of int
    | AfterChange of (int -> unit)
    interface IHTMLProp

let slickStyles = importAll<obj> "slick-carousel/slick/slick.scss"
let slickThemeStyles = importAll<obj> "slick-carousel/slick/slick-theme.scss"
let Slider = importDefault<ComponentClass<obj>> "react-slick/lib/slider"
let slider (b: IHTMLProp list) c = React.from Slider (keyValueList CaseRules.LowerFirst b) c

因此,虽然react-slick定义了一个属性InitialSlide来设置最初应该显示的幻灯片,但没有属性可以在之后更新幻灯片。有一种方法slickGoTo可以做我想做的事。但我不知道如何或在哪里调用该方法,同时仍符合 Elmish。

我可以想象我必须扩展反应组件并监听模型属性,然后slickGoTo在该属性更改时调用。但我不知道这是否可能。

所以我的问题是:如何slickGoTo在不破解 Elmish 架构的情况下使用由组件定义的按钮来更改单击时的幻灯片编号?

标签: reactjsf#fable-f#elmish

解决方案


为了能够调用该方法slickGoTo,您需要获取对滑块对象的引用。为此,请使用Ref需要 type 函数的道具(Browser.Element -> unit)。它被调用一次。将该元素保存在某处,可能在您的模型中:

type Model = {
    ...
    slideNumber : int
    sliderRef   : Browser.Element option
    ...
}

let gotoSlide sliderRef n = 
    match sliderRef with None ->
    | None -> () 
    | Some slider -> slider?slickGoTo n

这样你就可以gotoSlide从你的更新函数中调用。

type Msg =
| SetSliderRef of Browser.Element
| CurrentSlide of int
| GotoSlide    of int
...

let update msg model =
    match msg with
    | SetSliderRef e -> { model with sliderRef   = Some e }  , []
    | CurrentSlide n -> { model with slideNumber = n      }  , []
    | GotoSlide    n -> gotoSlide model.sliderRef n ;   model, []
    ...

像这样创建幻灯片:

slider 
    [ Ref          (SetSliderRef >> dispatch) 
      AfterChange  (CurrentSlide >> dispatch)
      InitialSlide 0
    ]
    slides

我还没有测试过任何这些,所以带上一粒盐。


推荐阅读