drcmda / react-contextual

🚀 react-contextual is a small (less than 1KB) helper around React 16s new context api
MIT License
642 stars 22 forks source link

Looking for contributors, maintainers, ideas ... #1

Open drcmda opened 6 years ago

drcmda commented 6 years ago

Reacts dynamic context is still new but due to its powerful nature lots of patterns and best practices will emerge from it. It can already make large parts of redux obsolete for instance (react-redux bindings, diffing mapStateToProps, ...) since React does so much out of the box now, although a little too low level perhaps to use it raw. I'm sure there are also interesting new ways to distribute and consume state in general.

If anyone is interested in exploring this, please drop a message! 😊

Lokua commented 6 years ago

I'm happy to help. There are few things I think this project could use that will help with collaboration:

I'd be down to do PRs for any of those things but you being the owner probably have some opinions and should really decide what kind of style you want your project to be written in.

drcmda commented 6 years ago

@Lokua that is awesome! Yes, please go ahead and make a PR. I'm fine with all your suggestions.

I currently use:

  "prettier": {
    "printWidth": 120,
    "tabWidth": 4,
    "useTabs": false,
    "semi": false,
    "singleQuote": true,
    "trailingComma": "all",
    "bracketSpacing": true,
    "jsxBracketSameLine": true
  },
erikthedeveloper commented 6 years ago

Hi @drcmda! I just came across react-contextual and found it compelling. Two thoughts that come to mind for me are:

1. Update README to use actual code snippet examples rather than just screenshots

This would make the README much easier to search through, make use of, and maintain.

2. Make render props more of a 1st class citizen to the API

At first glance, it is not apparent that render prop usage is supported. It's not until the bottom of the README when you mention render props almost in fine-print:

If you [...] dislike HOCs [...] do the same as above with render props

Considering the render prop patterns's rise in usage throughout the community and that React's context API is explicitly built around the concept of render props, I imagine it would be a great 1st class, recommended use, of react-contextual.


After skimming over the README (and discovering render prop support), this is how I understand and envision myself using react-contextual (one big selling point being able to create separate, standalone providers)

<Provider 
  id="food" 
  initialState={{eatCount: 0}} 
  actions={{eat: ({eatCount}) => ({eatCount: eatCount + 1})}}
  >
  <Provider 
    id="toys" 
    initialState={{playCount: 0}} 
    actions={{play: ({playCount}) => ({playCount: playCount + 1})}}
    >
    <Subscribe to="toys">
      {({playCount, play}) => 
        <button onClick={play}>Play: {playCount}</button>}
    </Subscribe>
    <Subscribe to="food">
      {({eatCount, eat}) => 
        <button onClick={eat}>Eat: {eatCount}</button>}
    </Subscribe>
  </Provider>
</Provider>

As I understand :arrow_up: would be supported by react-contextual as-is. If you like the sound of that I can put together a README focused PR to better emphasize this.

erikthedeveloper commented 6 years ago

Another thought that comes to mind is that I would typically define the majority of my state/actions somewhere at the top level "App" layer. I can envision some form of MultiProvider to guide/ease this process and avoid the nesting that many Providers would result in.

Example (assuming same "app contents" as above)


const foodProvider = {
  id: "food",
  initialState: {eatCount: 0},
  actions: {eat: ({eatCount}) => ({eatCount: eatCount + 1})},
};

const toysProvider = {
  id: "toys",
  initialState: {playCount: 0},
  actions: {play: ({playCount}) => ({playCount: playCount + 1})},
};

// As-is. One provider per Provider
<Provider {...foodProvider}>
  <Provider {...toysProvider}>
    {/* ... */}
  </Provider>
</Provider>

// Compose multiple providers. Typically used at the top "App" level.
<MultiProvider providers={[foodProvider, toysProvider /* ... */]}>
  {/* ... */}
</MultiProvider>
drcmda commented 6 years ago

Hi @erikthedeveloper, sure, go ahead with the PR! I think i went for screencaps cause githubs default formating looked tame, i thought it's harder to see what's going on on first glance. But you're right, being able to copy is worth it. All the examples are in the following folder in plain text: https://github.com/drcmda/react-contextual/tree/master/assets/examples

Making render-props more front and center is fine as well, let's try it! 😀

Last but not least, MultiProvider, i guess it wouldn't hurt. Though if i want to have both food and toys at the top level, why not merging state and actions in one store? Like

<Provider 
    initialState={{ ...toyState, ...foodState }}
    actions={{ ...toyActions, ...foodActions }}>
erikthedeveloper commented 6 years ago

Sounds good @drcmda. I'll see if I can get some time to put that README focused PR together this week.


On the concept of MultiProvider:

why not merging state and actions in one store?

That would eliminate what I see as the benefit of easily separating state/actions into different providers/stores. Of course, I haven't dug in and really used this lib myself yet but that separation seems to be one of the main appeals to me.

Spreading those on the same provider means one flat/giant store and potential problems with naming conflicts. Imagine:

const food = {
  initialState: {items: [/* ... */], loading: false},
  actions: {deleteItem: (id) => {/* delete food item */}}
};

const toys = {
  initialState: {items: [/* ... */], loading: false},
  actions: {deleteItem: (id) => {/* delete toys item */}}
};

// toys state.items, state.loading, and actions.deleteItem are over-written by food's same named properties
<Provider 
  initialState={{ ...toys.initialState, ...food.initialState }}
  actions={{ ...toys.actions, ...food.actions }}
/>

I feel like enabling a similar separation of state/actions such as redux reducers, flux stores, etc... is one of the goals of react-contextual which is why I might see an API to ease that usage worthwhile (vs. as-is which I understand would require nesting many Providers one for each store that you desire).

I suppose if we want to further explore the idea we should open an issue specific to discussing this concept of MultiProvider.

drcmda commented 6 years ago

@erikthedeveloper I've linked the images to their code snippet prototypes. Copy/paste is just a click away, but still gives a cleaner glance of what's going on.

abenhamdine commented 6 years ago

Hi @drcmda and thanks for this useful library. I would be happy to help on following things :

drcmda commented 6 years ago

@abenhamdine awesome, go ahead, that would be very useful.

d3dc commented 6 years ago

@drcmda I started looking at unstated after it got a bit popular. It has a bit of overlap with your library's stores, but it doesn't provide the context manipulation that this library does - I think it might be good to play up these features a bit better in the README potentially.


unstated does have one nice feature - Containers are instance-able with new state. I do wonder if stores should have this behavior.

The api in unstated is gnarlier (potentially more explicit) code

  <Provider inject={[new ThemeContainer({ color })]}