当模型 属性 改变时调用组件方法
Call component method when model property changes
在我的 Elmish 寓言应用程序中,我有一个使用 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。
我可以想象我必须扩展 React 组件并监听模型 属性,然后在 属性 发生变化时调用 slickGoTo
。但是不知道可不可以。
所以我的问题是:如何使用由组件定义的 slickGoTo
在点击时更改幻灯片编号的按钮,同时又不破坏 Elmish 架构?
为了能够调用方法 slickGoTo
,您需要获得对滑块对象的引用。要做到这一点,请使用 Ref
属性,该属性需要 (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
我还没有测试过这些,所以请三思而后行。
我刚刚发现您之前在 React 中使用 componentWillReceiveProps
解决了此类问题 - 这听起来很像我想要的 IMO。但这现在已经过时了,根据我的使用情况有两个建议:
If you used componentWillReceiveProps to “reset” some state when a prop changes, consider either making a component fully controlled or fully uncontrolled with a key instead.
我不认为我可以实现 Fully controlled
版本(这必须由组件的作者完成,对吧?),但 fully uncontrolled with a key
似乎可以工作。所以我的滑块视图现在看起来像这样:
Fable.Import.Slick.slider
[ InitialSlide model.SlideNumber
AfterChange (SlideTo >> dispatch)
Key (string model.SlideNumber) ]
根据文档,每次 Key
更改时,都会重新创建组件。现在这听起来开销很大并且有其自身的缺点(动画幻灯片不起作用)但目前它是最简单的解决方案。有什么顾虑吗?
在模型中存储对滑块对象的引用的另一种方法是使用可变变量:
let mutable sliderRef : Browser.Element option = None
let gotoSlide n =
match sliderRef with None ->
| None -> ()
| Some slider -> slider?slickGoTo n
其余类似:
type Msg =
| CurrentSlide of int
| GotoSlide of int
...
let update msg model =
match msg with
| CurrentSlide n -> { model with slideNumber = n } , []
| GotoSlide n -> gotoSlide n ; model, []
像这样创建你的滑块:
slider
[ Ref (fun slider = sliderRef <- Some slider)
AfterChange (CurrentSlide >> dispatch)
InitialSlide 0
]
slides
在我的 Elmish 寓言应用程序中,我有一个使用 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。
我可以想象我必须扩展 React 组件并监听模型 属性,然后在 属性 发生变化时调用 slickGoTo
。但是不知道可不可以。
所以我的问题是:如何使用由组件定义的 slickGoTo
在点击时更改幻灯片编号的按钮,同时又不破坏 Elmish 架构?
为了能够调用方法 slickGoTo
,您需要获得对滑块对象的引用。要做到这一点,请使用 Ref
属性,该属性需要 (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
我还没有测试过这些,所以请三思而后行。
我刚刚发现您之前在 React 中使用 componentWillReceiveProps
解决了此类问题 - 这听起来很像我想要的 IMO。但这现在已经过时了,根据我的使用情况有两个建议:
If you used componentWillReceiveProps to “reset” some state when a prop changes, consider either making a component fully controlled or fully uncontrolled with a key instead.
我不认为我可以实现 Fully controlled
版本(这必须由组件的作者完成,对吧?),但 fully uncontrolled with a key
似乎可以工作。所以我的滑块视图现在看起来像这样:
Fable.Import.Slick.slider
[ InitialSlide model.SlideNumber
AfterChange (SlideTo >> dispatch)
Key (string model.SlideNumber) ]
根据文档,每次 Key
更改时,都会重新创建组件。现在这听起来开销很大并且有其自身的缺点(动画幻灯片不起作用)但目前它是最简单的解决方案。有什么顾虑吗?
在模型中存储对滑块对象的引用的另一种方法是使用可变变量:
let mutable sliderRef : Browser.Element option = None
let gotoSlide n =
match sliderRef with None ->
| None -> ()
| Some slider -> slider?slickGoTo n
其余类似:
type Msg =
| CurrentSlide of int
| GotoSlide of int
...
let update msg model =
match msg with
| CurrentSlide n -> { model with slideNumber = n } , []
| GotoSlide n -> gotoSlide n ; model, []
像这样创建你的滑块:
slider
[ Ref (fun slider = sliderRef <- Some slider)
AfterChange (CurrentSlide >> dispatch)
InitialSlide 0
]
slides