Coder Social home page Coder Social logo

react-container's Introduction

Import as

import container from 'buildo-react-container'

All the following should be valid usage examples

export default container(MyComponent)
export default container(MyComponent, {
  connect: { param1: Type1 }
})
export default container(MyComponent, {
  mapProps: ({ a, b }) => ({ aAndB: `${a}&${b}` })
})
export default container(MyComponent, {
  queries: ['query1', 'query2']
})
export default container(MyComponent, {
  commands: ['cmd1']
})

This could be a "typical" usage

export default container(MyComponent, {
  connect: { a: t.String },
  mapProps: ({ a, b, cmd1 }) => ({
    aAndB: `${a}&${b}`,
    onClick: cmd1
  }),
  queries: ['b'],
  commands: ['cmd1']
})

Usage on node and/or SSR project:

When we have a single render shot (SSR on node), we must opt-in to querySync so that at the first render we have all the data we need to produce a full HTML. See also https://github.com/buildo/react-avenger/blob/master/src/queries.js#L38-L47

export default container(MyComponent, {
  querySync: true,
  queries: ['b']
})

If you need to add additional prop types...

(other than the ones derived from queries/commands/connect)

export default container(MyComponent, {
  propTypes: { myProp: MyType },
  // ...
});

Use this forms to configure react-avenger/queries, react-avenger/commands or state/connect

This should be done only once in a project, typically in a custom app/container file or folder.

const containerFactory = container({
  declareConnect: declareConnect(/* declareConnect config */)
  allQueries: { /* all queries */ },
  allCommands: { /* all commands */ }
})

export default containerFactory(MyComponent, {
  /* container cfg */
})

Notes about caching query values in a container instance

When we declare queries in a container we are delegating to avenger (and the query definition) the decision about refetching or not, given a possibly outdated value currently available in the cache.

From the container (component) perspective instead, closer to rendering the actual UI, we have slightly different concerns:

  • should we render a loader if data is nota vailable yet?
  • should we render loading states alongside UI for the data if we are both "loading" and "ready to render"
  • should we wait for "fresh" data before rendering (i.e. if we are both "loading" and "ready to render", should we wait for the updated values aka to be "not loading anymore")

These kind of things are generally solved by customizing a loading decorator, that normally receives the plain data and readyState as avenger produces it.

There are specific cases though, where, as a container instance currently rendering some UI, we need to manipulate intermediate/stale data obtained from avenger before feeding it into our UI/loading. container is per se stateless. Here we need instead to accumulate state between multiple container re-renderings. In this cases we should resort to the reduceQueryProps api:

container(MyComponent, {
  reduceQueryProps: (accumulator: Any, propsFromQueries: PropsFromQueries) => ({
    accumulator: Any,        // accumulator for the next re-render, if needed
    props: PropsFromQueries  // the actual props passed down at this render: you can map/change `readyState` and any query as you wish here
  })
})

Since there are only a few useful known usages, here we'll just list them and explain the use case.

default (no reduceQueryProps)

In the large majority of cases, this is what we want. As soon as we have a value for a query, we'll pass it down. As soon as some event causes the query the refetch, we'll pass the readyState.loading state down as well. We stay stateless.

If the query is refetched with a different input, we'll get notified and loose the previous value we got (it was indeed for a different input) and we pass through a "no data" state. This last example is uncommon since typically, during the whole container lifecycle, inputs for the queries it declares do not change.

cache query values

When the lifecycle of the component spans multiple instances of the same query class (i.e.: the declared query is refetched with different inputs while we are still mounted), we'll typically want to preserve data (and thus UI) across multiple instances.

Two example use cases to clarify:

  • A query that produces a value also based on user input. User writes in a form, the query refetches with new inputs at every keystroke, we need to keep rendering the value computed, even if it was for the previous input.
  • When we have data arranged in a sortable list, and the sorting is performed by the api: if the user sorts by a different param, we'll typically want to:
    • (maybe) show a loader while we are retrieving the updated sorted results
    • keep showing the stale data we have (in other words: avoid passing by "empty list" states, while waiting for the re-sorted data)

For this scenario, container exports a custom reduceQueryProps function called cacheQueryValues. It can be used as follows:

import container, { cacheQueryValues } from 'container';

container(MyComponent, {
  queries: ['sortedData'],
  reduceQueryProps: cacheQueryValues,
  // ...
})

react-container's People

Contributors

giogonzo avatar veej avatar francescocioria avatar francescogior avatar

Stargazers

Adriano Machado avatar

Watchers

James Cloos avatar  avatar  avatar

react-container's Issues

local state is not cleared on component unmount

description

{describe the buggy behavior}

how to reproduce

  • {optional: describe steps to reproduce bug}

specs

{optional: describe a possible fix for this bug, if not obvious}

misc

{optional: other useful info}

local state should be instance-specific and not class-specific

description

Right now local state is defined at class level, meaning that every instance of the same container will access the same local variables.
What we want instead is a local state bounded to a particular instance of a container, i.e. different instances will access different local variables.

how to reproduce

  • Render two instance of a container with local state. Change the local state from the first instance. Changes will reflect on the second instance too.

specs

misc

{optional: other useful info}

support for https://github.com/buildo/react-avenger/pull/26

requirements

{describe the new feature}

specs

in container we now have to make sure to connect all what's needed by queries and command too (other than just connect), and then be kind and filter out any possibly unwanted prop before rendering the component (mapProps)

misc

{optional: other useful info}

add "local" api

requirements

as discussed offline, it should:

  • “exists” only while the container exists
    • Note: as a first implementation, this requirement has been relaxed a bit, so local state is 1:1 with a container instance (a container(Component) class), not with a container(Component) instance. In other words, if you have multiple copies of the same container rendered at the same time, they all share the same "local" state
  • be accessible from the single container, no other container can (easily) access it
  • local state params should still be accessible to queries as params, with their local names

specs

{optional: describe technical specs to implement this feature, if not obvious}

misc

{optional: other useful info}

update to versioned `buildo-state`

requirements

as per title, instead of depending on github:buildo/state#v0.2.0

specs

{optional: describe technical specs to implement this feature, if not obvious}

misc

{optional: other useful info}

bump buildo-state version

requirements

{describe the new feature}

specs

{optional: describe technical specs to implement this feature, if not obvious}

misc

{optional: other useful info}

add `freshValuesOnly` `reduceQueryProps` function

requirements

We now have also cacheQueryValues, that caches previous defined values obtained from queries in the container instance.
This new helper would instead force the values passed to the underlying container mapProps to be either: { loading: true } or { loading: false, data: ... }
In other words, only pass "fresh" values down, never pass stale values (obtained in a previous fetch)

specs

first of all, this requires the logic in reduceQueryProps/decorator to be updated slightly:

then, the logic for this reducer should be something like:

  • if loading = true, then pass down an undefined data
  • if loading = false, then pass down whatever data we have at hand
    also, the readyState, ready in particular, should be updated accordingly

misc

{optional: other useful info}

replace tcomb with io-ts

requirements

{describe the new feature}

specs

{optional: describe technical specs to implement this feature, if not obvious}

misc

{optional: other useful info}

make this a real package, versioned on npm

requirements

As per title.
It should allow us to change api more easily and spare us some headache with yarn, npm & co

specs

  • use smooth-release for changelog, etc
  • publish to npm
  • update version on projects currently using it (qia, ams, lexdoit)

misc

{optional: other useful info}

add `pure = true` to container api

requirements

it should never be used, but still there are a few remote legit use cases, e.g.:

  • backporting an app still using Containers as RouteHandlers, one should be allowed to create a (temporarily!) impure container

specs

  • it should default to true
  • it should omit @pure if pure = false

misc

  • to customize connect purity one still needs to pass an impure declareConnect manually
  • this should be backported to old 0.5.x version too

Clean up local state

description

While this should hardly create bugs, it's something against the initial goals of the local state feature.

After #63 local keys are set to undefined but they are removed from the container namespaced object. Also, empty namespaced objects should be removed entirely

support `defaultProps`

requirements

Currently there's no way to apply default props at container level.

This is usually solved at mapProps level using default assignments, as in { val = default },
but has no effect on what happens "above" mapProps: queries, commands.

In other words, there's no way to specify default params for declared queries/commands
(the only way remains by passing them via props from outside when rendering the container).
It would be nice to add this as a short-hand

specs

  • add defaultProps to container config options
  • apply this default props to the generated component
  • everything else should already work as is

misc

{optional: other useful info}

breaking to update buildo-state version

requirements

{describe the new feature}

specs

{optional: describe technical specs to implement this feature, if not obvious}

misc

{optional: other useful info}

fix transition on local

description

localizeProps method redefine the transition method updating the ___local object starting from the version connected to the component.
If the transition call is delayed, the connected ___local object could be out-of-date, and the transition will overwrite the updates.

cleanProps is not working

description

this logic is buggy becausequeriesInputTypes and commandsInputTypes are arrays, not objects

how to reproduce

  • log every prop in a container that defines queries and commands -> there will be more props than you declared

specs

use concat :)

misc

{optional: other useful info}

add a build step

requirements

in order to avoid special handling for this package in every project's webpack config

specs

  • add babel and prepublish and .npmignore

misc

{optional: other useful info}

Support new state API

requirements

react-container must be adapted to the new state API: buildo/state#28

specs

  • connect should be adapted to accept a list of fields, instead of a map of fields with types.
  • local should be rethought to save every local state inside a ___local key of the global state. In this way we can validate the global state adding a single line ___local: t.Any to the StateType

misc

{optional: other useful info}

container should not connect to every query/command input param

description

At this moment, react-container is trying to connect to every query/command's input param, even those that are not coming from state.
This was not a problem since the refactoring of buildo/state, where we're checking that every global variable we connect to is actually declared in the AppState.
For this reason, we have been forced to add fake variables to the AppState, just to make buildo/state happy (e.g. https://github.com/buildo/gdsm/pull/586/files#diff-7f68bc23c5c95c78faf131f41d102221R13)

how to reproduce

  • Remove fake variables from the AppState in GDSM or AlinityPro and npm start

specs

react-container should know the AppState and connect only to the input params that are declared in state.

misc

{optional: other useful info}

update buildo-state dependency

description

{describe the buggy behavior}

how to reproduce

  • {optional: describe steps to reproduce bug}

specs

{optional: describe a possible fix for this bug, if not obvious}

misc

{optional: other useful info}

Handle default values for queries

requirements

  • devs should be able to handle default values for props coming from queries
  • devs should be able to handle old values for props coming from queries

specs

  • add optional preMapProps to container config params
    • function that takes as arguments all the props (like mapProps) but keep also the last not-Nil values for all the queries values
    • returned value will be passed to mapProps
  • add optional cacheQValues boolean flag
    • if true, preMapProps will be defaulted to x => x (identity);
    • if preMapProps is provided, cacheQvalues is ignored

replace `__DO_NOT_USE_additionalPropTypes` with `propTypes`

requirements

Current naming is unnecessarily scary, we found legit use cases where one needs to pass additional props

specs

  • just change the config key

misc

Other than propTypes (__DO_NOT_USE_additionalPropTypes), the prop types for a container component are derived from the various declarations: connect (as expected), queries (every possible query param is both connected and a valid prop to pass to the container component), commands (same as queries)

local is trying to delete what's not there on unmount

description

screen shot 2017-05-16 at 10 13 32 am

`TypeError: Cannot convert undefined or null to object`

how to reproduce

  • {optional: describe steps to reproduce bug}

specs

check if this.props.[k] is there before trying to access it

misc

{optional: other useful info}

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.