Permalink
Browse files

[WIP] Make `to` in `<Subscribe>` support `Container` instances

  • Loading branch information...
sindresorhus authored and jamiebuilds committed Mar 1, 2018
1 parent 9b4ac86 commit d070a9d914b221aa458dfb9c0289c2ea482e10d1
Showing with 90 additions and 8 deletions.
  1. +1 −1 README.md
  2. +19 −0 __tests__/unstated.tsx
  3. +4 −0 example/index.html
  4. +43 −0 example/shared.js
  5. +23 −7 src/unstated.js
@@ -219,7 +219,7 @@ Next we'll need a piece to introduce our state back into the tree so that:
* We can call methods on our container.
For this we have the `<Subscribe>` component which allows us to pass our
container classes and receive instances of them in the tree.
container classes/instances and receive instances of them in the tree.
```js
function Counter() {
@@ -69,6 +69,25 @@ function CounterWithAmountApp() {
);
}
const sharedAmountContainer = new AmountContainer();
function CounterWithSharedAmountApp() {
<Subscribe to={[sharedAmountContainer]}>
{(amounter: AmounterContainer) => (
<div>
<Counter />
<input
type="number"
value={amounter.state.amount}
onChange={event => {
amounter.setAmount(parseInt(event.currentTarget.value, 10));
}}
/>
</div>
)}
</Subscribe>
);
}
let counter = new CounterContainer();
let render = () => (
<Provider inject={[counter]}>
@@ -12,5 +12,9 @@ <h3>Simple</h3>
<h3>Complex</h3>
<div id="complex"></div>
<script type="text/javascript" src="./complex.js"></script>
<h3>Shared</h3>
<div id="shared"></div>
<script type="text/javascript" src="./shared.js"></script>
</body>
</html>
@@ -0,0 +1,43 @@
// @flow
import React from 'react';
import { render } from 'react-dom';
import { Provider, Subscribe, Container } from '../src/unstated';
type CounterState = {
count: number
};
class CounterContainer extends Container<CounterState> {
state = { count: 0 };
increment() {
this.setState({ count: this.state.count + 1 });
}
decrement() {
this.setState({ count: this.state.count - 1 });
}
}
const sharedCounterContainer = new CounterContainer();
function Counter() {
return (
<Subscribe to={[sharedCounterContainer]}>
{counter => (
<div>
<button onClick={() => counter.decrement()}>-</button>
<span>{counter.state.count}</span>
<button onClick={() => sharedCounterContainer.increment()}>+</button>
</div>
)}
</Subscribe>
);
}
render(
<Provider>
<Counter />
</Provider>,
window.shared
);
@@ -24,12 +24,14 @@ export class Container<State: {}> {
}
export type ContainerType = Container<Object>;
export type ContainersType = Array<Class<ContainerType>>;
export type ContainersType = Array<Class<ContainerType> | ContainerType>;
export type ContainerMapType = Map<Class<ContainerType>, ContainerType>;
export type SubscribeProps<Containers: ContainersType> = {
to: Containers,
children: (...instances: $TupleMap<Containers, <C>(Class<C>) => C>) => Node
children: (
...instances: $TupleMap<Containers, <C>(Class<C> | C) => C>
) => Node
};
type SubscribeState = {};
@@ -75,12 +77,26 @@ export class Subscribe<Containers: ContainersType> extends React.Component<
}
let safeMap = map;
let instances = containers.map(Container => {
let instance = safeMap.get(Container);
let instances = containers.map(ContainerItem => {
let instance: ContainerType;
if (
typeof ContainerItem === 'object' &&
ContainerItem instanceof Container
) {
instance = ContainerItem;
let Class = instance.constructor;
if (!safeMap.has(Class)) {
safeMap.set(Class, instance);
}
} else {
instance = (safeMap.get(ContainerItem): any);
if (!instance) {
instance = new Container();
safeMap.set(Container, instance);
if (!instance) {
instance = new ContainerItem();
safeMap.set(ContainerItem, instance);
}
}
instance.unsubscribe(this.onUpdate);

0 comments on commit d070a9d

Please sign in to comment.