fable-compiler / fable-react

Fable bindings and helpers for React and React Native
MIT License
273 stars 67 forks source link

Add API for React.Context #160

Closed DemiusAcademius closed 5 years ago

DemiusAcademius commented 5 years ago

It would be nice if we had a helper for React.Context API: https://reactjs.org/docs/context.html and https://reactjs.org/docs/hooks-reference.html#usecontext Thanks for powerfull soft

alfonsogarciacaro commented 5 years ago

Actually, I was considering to add that hook but didn't do it because I don't know well how the Context API work. I'll try to read a bit more and implement it, thanks for the links!

alfonsogarciacaro commented 5 years ago

Another question is how this would work with SSR, because we're trying to make all helpers in this library SSR compatible.

alfonsogarciacaro commented 5 years ago

On a quick look it doesn't look as a good fit for Elmish apps, because this kind of information usually goes in the model and using React's context may require several static references which may be even difficult because of file order in F#. Do you have an example on how React's context could work in a Fable React app?

DemiusAcademius commented 5 years ago

ReactContext types from original React (Flowtype) https://github.com/facebook/react/blob/master/packages/shared/ReactTypes.js

(may be in Consumer: ReactContext, error)

export type ReactProvider = { $$typeof: Symbol | number, type: ReactProviderType, key: null | string, ref: null, props: { value: T, children?: ReactNodeList, }, };

export type ReactProviderType = { $$typeof: Symbol | number, _context: ReactContext, };

export type ReactConsumer = { $$typeof: Symbol | number, type: ReactContext, key: null | string, ref: null, props: { children: (value: T) => ReactNodeList, unstable_observedBits?: number, }, };

export type ReactContext = { $$typeof: Symbol | number, Consumer: ReactContext, Provider: ReactProviderType,

_calculateChangedBits: ((a: T, b: T) => number) | null,

_currentValue: T, _currentValue2: T, _threadCount: number,

// DEV only _currentRenderer?: Object | null, _currentRenderer2?: Object | null, };

DemiusAcademius commented 5 years ago

Another link to React.CreateContext: https://github.com/facebook/react/blob/master/packages/react/src/ReactContext.js

DemiusAcademius commented 5 years ago

Context API in ReasonReact:

https://github.com/reasonml/reason-react/blob/master/src/React.re

module Context = { type t('props);

[@bs.get] external provider: t('props) => component({ . "value": 'props, "children": element, }) = "Provider"; };

[@bs.module "react"] external createContext: 'a => Context.t('a) = "";

DemiusAcademius commented 5 years ago

Unfortunately I do not have enough knowledge to do it in F#

DemiusAcademius commented 5 years ago

But I use Context in React with Typescript for global authentication context and for pass props of component to child of child of child etc (without Redux or Mobx, but strongly typed)

nojaf commented 5 years ago

I'm also interested in this feature. I've made a small sample https://github.com/nojaf/react-context-sample Bindings are not perfect but perhaps they can serve as a starting point.

DemiusAcademius commented 5 years ago

Thanks! It turns out to be very simple. But I overloaded everything

alfonsogarciacaro commented 5 years ago

Thanks @nojaf! That's a very good example of how React context should work in F#, I'll follow that to add the bindings to Fable.React :+1:

alfonsogarciacaro commented 5 years ago

I've added the Context API in 5.2.1 and tried to make it compatible with SSR. You can see a usage example here: https://github.com/fable-compiler/fable-react/commit/3dfbd761f1b01cba0934a6f2aef3ca918a14f6bc#diff-fbdb47a7fd0afc448eba000af59b0221