Code Monkey home page Code Monkey logo

Comments (16)

danyx23 avatar danyx23 commented on August 20, 2024 2

@alfonsogarciacaro cool I'll draft a PR in the next few days. I can't really comment on the finer points yet but I'll go over the docs again and look at some usage, maybe I will have a bit more input then.

@forki it's a silly name but it what is used in the official react docs: https://reactjs.org/docs/higher-order-components.html. As such I would stay with higher order components as that is what people coming from react would be looking for and how third party components that follow this pattern would describe themselves.

from fable-react.

danyx23 avatar danyx23 commented on August 20, 2024 2

I added a first draft of the docs - please let me know what you think!

from fable-react.

alfonsogarciacaro avatar alfonsogarciacaro commented on August 20, 2024 1

Thanks a lot for your comments! Yes, so far we've tried to closely follow the React terminology to prevent mismatches with React documentation. We should keep the reference to HOC in this case here too.

from fable-react.

alfonsogarciacaro avatar alfonsogarciacaro commented on August 20, 2024

Hi @danyx23! You're right, we have the pieces to easily import React components but we're missing the guide to do it. There are currently two ways to do it:

  • Dynamically: Just import the component and define the properties with a pojo. A mini-guide to do that can be found here.
  • Creating bindings: If you plan to use the component a lot, it maybe worthy to write some bindings to use DUs for the props and get more idiomatic F#. We're missing a guide for it (maybe @Zaid-Ajaj was writing one) although you can check other bindings in this repo (like the one for Leaflet). The most important thing is to call keyValueList before passing the prop list to the imported component (as in here).

EDIT: @danyx23 documented how to use 3rd party React components. You can also see below an example of importing HOC components.

from fable-react.

danyx23 avatar danyx23 commented on August 20, 2024

Hi @alfonsogarciacaro, thank your for your reply! How do you suggest to go forward with this? Should I create a PR with an initial draft of a documentation document in the docs folder of this repo that outlines how to use a third party react component?

I am relatively new to Fable and have only used React a little bit - are there areas that are more tricky, like HOCs or similar somewhat advanced features of React?

from fable-react.

alfonsogarciacaro avatar alfonsogarciacaro commented on August 20, 2024

This is funny, I was about to write that I hadn't used React HOCs so I didn't know, but just today I had to use them in my project and realized we're missing a helper in fable-react. I think we could add something like this:

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

// Helper to be added to fable-react
let importHigherOrderComponent<[<Pojo>]'P> (importMember: string) (importPath: string) (fn: 'P->ReactElement): ComponentClass<'P> = jsNative

type [<Pojo>] MyProps =
    { index: int; value: string }

let SortableItem: ComponentClass<MyProps> =
    importHigherOrderComponent "SortableElement" "react-sortable-hoc" (fun p ->
        li [] [str p.value])

// To be used like...
let render () =
    from SortableItem { index = 1; value = "foo" } []

But I'm not sure about a few things:

  • Name? importHigherOrderComponent or something else?
  • Only for imported components or also accepting ComponentClass?
  • The generic 'Props of the returned HOC should be always the same as the argument of the function argument?
  • Probably we also need to add a helper alias instead of from like ofType, ofFunction... Maybe ofComponent here?

@zaaack @MangelMaxime what do you think?

@danyx23 About the documentation, if you could send a PR that'd be great. Don't worry too much about the details, we can work on that later together. The important thing to keep in mind is Fable compiles directly to JS, not JSX. So usually calling React.createElement, passing the component as the first element, a plain JS object containing the props, and filling the rest of arguments with children (as the fable-react helpers do) usually works.

from fable-react.

MangelMaxime avatar MangelMaxime commented on August 20, 2024

I never used HOC so I don't know and don't really understand the hight order think.

from fable-react.

alfonsogarciacaro avatar alfonsogarciacaro commented on August 20, 2024

@MangelMaxime They're used for example for react-sortable-hoc.

from fable-react.

forki avatar forki commented on August 20, 2024

from fable-react.

zaaack avatar zaaack commented on August 20, 2024

I know react-sortable-hoc, but never use it before. I'm OK with the naming, but not sure about the details, it's a rare case for me, but it looks really useful.

from fable-react.

alfonsogarciacaro avatar alfonsogarciacaro commented on August 20, 2024

I forgot to mention @vbfox to know his opinion about the helper for React HOCs (please see comment above).

from fable-react.

runefs avatar runefs commented on August 20, 2024

Did you make any progress on the importHigherOrderComponent? Was look for a way to integrate react-sortable-hoc into my project to day and found this thread but couldn't figure out whether you have implemented it y a different name

from fable-react.

MangelMaxime avatar MangelMaxime commented on August 20, 2024

Look at this comments: #84 (comment)

I think it should give you a solution

from fable-react.

alfonsogarciacaro avatar alfonsogarciacaro commented on August 20, 2024

@runefs We haven't added the helper yet to Fable.React but here's how I'm using react-sortable-hoc in my project, hope it helps:

Using react-sortable-hoc from Fable
open Fable.Helpers.React
open Fable.Core.JsInterop

/// Ugly helper that should be moved to fable-react
let inline hocOfImport<'P> (importMember: string) (importPath: string) (fn: 'P->ReactElement): ComponentClass<'P> =
    !!((import importMember importPath) $ fn)

// let arrayMove(xs: 'a[], oldIndex: int, newIndex: int): 'a[] = importMember "react-sortable-hoc"

type SortableElementProps<'a> =
    {
      // SortableElement HOC props (cannot be used by wrapped component)
      // https://github.com/clauderic/react-sortable-hoc#sortableelement-hoc
      index: int
      disabled: bool
      // Custom props
      rowIndex: int
      key: string
      value: 'a
      handle: ComponentClass<unit>
      renderItem: ComponentClass<unit> -> int -> 'a -> ReactElement
    }

type SortEnd =
    { oldIndex: int
      newIndex: int }

type SortableContainerProps<'a> =
    {
      // SortableContainer HOC props (cannot be used by wrapped component)
      // https://github.com/clauderic/react-sortable-hoc#sortablecontainer-hoc
      onSortEnd: SortEnd->unit
      lockAxis: string
      // Custom props
      items: 'a list
      handle: ComponentClass<unit>
      useDragHandle: bool
      renderItem: ComponentClass<unit> -> int -> 'a -> ReactElement
      renderList: ReactElement list -> ReactElement
      disabled: bool
    }


let mkSortableHandle (f: unit -> ReactElement) =
    hocOfImport "SortableHandle" "react-sortable-hoc" f


let mkSortableElement<'a> () =
    hocOfImport "SortableElement" "react-sortable-hoc"
        (fun (p: SortableElementProps<'a>) -> p.renderItem p.handle p.rowIndex p.value)


let mkSortableContainer<'a> (sortableElement: ComponentClass<SortableElementProps<'a>>) =
    hocOfImport "SortableContainer" "react-sortable-hoc"
        (fun (p: SortableContainerProps<'a>) ->
            p.items |> List.mapi (fun i v ->
                let a =
                    {
                      index = i
                      disabled = p.disabled
                      rowIndex = i
                      key = "item-" + string i // TODO: unique keys not depending on order
                      value = v
                      handle = p.handle
                      renderItem = p.renderItem
                    }
                from sortableElement a [])
            |> p.renderList)


type SortableComponentProps<'a> =
    {
        renderHandle: unit->ReactElement
        renderItem: ComponentClass<unit> -> int -> 'a -> ReactElement
        renderList: ReactElement list -> ReactElement
        items: 'a list
        /// oldIndex: int -> newIndex: int -> unit
        handleSortChanged : int -> int -> unit
        disabled: bool
    }


type SortableComponent<'a>(p) =
    inherit React.PureComponent<SortableComponentProps<'a>, unit>(p)
    // Cache the SortableContainer HOC in the constructor so it's only necessary to build it once
    let sortableContainer = mkSortableElement () |> mkSortableContainer
    let sortableHandle = mkSortableHandle p.renderHandle


    override this.render() =
        from sortableContainer
            {
                // arrayMove(List.toArray this.props.items, i.oldIndex, i.newIndex)
                onSortEnd  = fun i -> this.props.handleSortChanged i.oldIndex i.newIndex
                lockAxis   = "y"
                items      = this.props.items
                handle     = sortableHandle
                useDragHandle = true
                renderItem = this.props.renderItem
                renderList = this.props.renderList
                disabled   = this.props.disabled
            } []

/// handleSortChanged: oldIndex: int -> newIndex: int -> unit
let mkSortable
    (enabled: bool)
    (renderList: ReactElement list -> ReactElement)
    (renderItem: ComponentClass<unit> -> int -> 'a -> ReactElement)
    (renderHandle: unit -> ReactElement)
    (items: 'a list)
    (handleSortChanged: int -> int -> unit) =

    ofType<SortableComponent<'a>,_,_>
        {
            renderHandle = renderHandle
            renderItem = renderItem
            renderList = renderList
            items = items
            handleSortChanged = handleSortChanged
            disabled = not enabled
        } []

from fable-react.

olivercoad avatar olivercoad commented on August 20, 2024

Using a discriminated union props type as documented in using-third-party-react-components.md, how do you add support for IHTMLProp?
Fulma has a Props of IHTMLProp list case in the options DU types but I'm not sure how to do that for 3rd party react components.

from fable-react.

alfonsogarciacaro avatar alfonsogarciacaro commented on August 20, 2024

Unfortunately this involves a bit of a trick at the moment. When passing the props to react we need to convert them to a JS object, which is done with keyValueList. Right now, props nested in another union case are not supported by default, so you have to make the conversion by cheating the compiler as it's done for example here with the Style props:

#if !FABLE_COMPILER
| Style of CSSProp list
| Data of string * obj
#endif
interface IHTMLProp
#if FABLE_COMPILER
let inline Style (css: CSSProp list): HTMLAttr =
!!("style", keyValueList CaseRules.LowerFirst css)

from fable-react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.