Before this commit, an unwanted behaviour happened when using components
with shouldUpdate implemented, and store/state.
The actual problem is the following: the sub component is using a store,
and shouldupdate. Whenever the component is rendered, it checks if there is an incoming
rendering from the context. If that is the case, it skips the
rendering, because we actually only want to be rendered by the store
rendering (otherwise, we may run into issue with inconsistent data (more
recent data from the context, older data in the component).
However, if shouldUpdate is implemented, then the rendering coming from
the context simply does not arrive.
To fix this, we tried to just force these renderings to go through all children,
regardless of their shouldUpdate status. This actually works, but then
shouldUpdate is ignored, which is an issue in Odoo discuss.
Then, after discussing this situation, we noticed that the context/store
system is actually unsafe: the protection given by the check mentioned
above is in fact fundamentally insufficient: there are other perfectly
valid situations where a rendering can be triggered on the component,
which will bypass the check (for example, an explicit call to
this.render() or a rendering initiated by some parent component) and
cause a crash if the component is not properly defensively written.
Therefore, it is currently mandatory for all components using
context/store to be aware of that, and to protect themselves against
such situations. So, in that regard, the check is not really a
protection, it just helps hiding an unsafe situation anyway and we
decided to remove it.
Note that this is a potentially breaking change: components using a
store and some local state will now be rendered twice in some cases...
closes#799
Before this commit, Env was an indexed type, this means that one could
write env.anything, and it would accept it as a valid type. This is
actually quite dangerous, because we lose the typing advantages for all
keys that are properly defined.
For example, if a component is defined as:
class MyComponent extends Component<Props> {
...
}
Then Typescript will let it use anything from the environment, even if
it is wrong. So, most properly typed Typescript applications should use
instead a sub environment:
interface MyAppEnv extends Env {
someKey: someValue
}
Then, the component should be defined this way:
class MyComponent extends Component<Props, MyAppEnv> {
...
}
Before this commit, any typos in the environment accesses would not be
noticed by typescript.
In most cases, we just want Component<any, Env>. But since it was so
annoying to have always the type Env, we actually used
Component<any,any> everywhere.
With this commit, the generic types have a default (and their order is
swapped), so we can simply use Component in most cases, and
Component<Props> when we want to type the props.
We don't see any usecase for it, it makes the code more complex,
and there were still potential unresolved concurrency issues with
it.
Part of task #295
There were big issues when we use parent/child connected widgets.
- children was rendered twice (and mapStoreToProps was called twice)
- if children was supposed to be destroyed, it was rendered once.
We solve them in this commit by waiting for parent widgets to be ready
before updating children.
closes#216
Connected component should have a unique name. To achieve this the
connected component currently have an id based generated name (like
`ConnectedComponent1`).
To make it clearer and ease debugging this commit reuse the extended
component's name to include it in the generated name in the form of
`Connected<ComponentName>`.
This rev. add a 'set' and 'delete' static functions to the Observer.
They allow to set or delete (only for objects) properties on
observed objects or arrays.
With this, the 'set' functions in Store and Component are no longer
necessary, so they have been removed.
Closes#138
Before this commit, we tried to use a hash function for non observable
values, but this was not correct, since some changes could be done that
would compensate each other.
With this commit, we properly compare each non observable value.
With this commit, we can now decides precisely if a component should be
rerendered, by using a hash function.
By default, the hash function will deep observe each store element
coming from the result of the mapStateToProps.
closes#24