Skip to content

Commit

Permalink
feat(react): createContextHandler and withContext HOC + changes to Da…
Browse files Browse the repository at this point in the history
…taHandler

affects: @tao.js/react

DataHandler refactored to use createContextHandler underneath
Expose logic creating a Context used by DataHandler by exporting createContextHandler
createContextHandler works like a TAO version of React.createContext
createContextHandler uses normalizeAC & cleanInput
withContext HOC for wrapping components (not yet tested)
  • Loading branch information
eudaimos committed Nov 2, 2018
1 parent 1d2d484 commit b3a2827
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 26 deletions.
38 changes: 12 additions & 26 deletions packages/react-tao/src/DataHandler.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,37 @@
import React, { Component, createContext } from 'react';
import { AppCtx } from '@tao.js/core';
import React, { Component } from 'react';

import { normalizeAC, cleanInput } from './helpers';
import { Context } from './Provider';
import createContextHandler from './createContextHandler';

export default class DataHandler extends Component {
static contextType = Context;

constructor(props) {
super(props);
this.state = props.default || {};
this.ChildContext = createContext(this.state);
this.ChildContext = createContextHandler(
props,
props.handler,
props.default
);
}

componentWillMount() {
const trigram = cleanInput(normalizeAC(this.props));
const { TAO, setDataContext } = this.context;
const { name } = this.props;
const { setDataContext } = this.context;
setDataContext(name, this.ChildContext);
TAO.addInlineHandler(trigram, this.handleData);
}

componentWillUnmount() {
const trigram = cleanInput(normalizeAC(this.props));
const { TAO, removeDataContext } = this.context;
const { name } = this.props;
const { removeDataContext } = this.context;
removeDataContext(name);
TAO.removeInlineHandler(trigram, this.handleData);
}

handleData = (tao, data) => {
const { handler } = this.props;
const dataUpdate = handler
? handler(tao, data, data => this.setState(data))
: data;
if (dataUpdate instanceof AppCtx) {
return dataUpdate;
}
if (dataUpdate != null) {
const newState = Object.assign({}, this.state, dataUpdate);
this.setState(newState);
}
};

render() {
const { children } = this.props;
const Provider = this.ChildContext.Provider;
// use React.Children here to inject the context somehow?
// https://reactjs.org/docs/react-api.html#reactchildren
return <Provider value={this.state}>{children}</Provider>;
return <Provider>{children}</Provider>;
}
}
67 changes: 67 additions & 0 deletions packages/react-tao/src/createContextHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { Component } from 'react';
import cartesian from 'cartesian';
import { AppCtx } from '@tao.js/core';

import { normalizeAC, cleanInput } from './helpers';
import { Context } from './Provider';

export default function createContextHandler(tao, handler, defaultValue) {
if (typeof handler !== 'function') {
throw new Error('createContextHandler `handler` must be a function');
}
const WrappingContext = React.createContext(defaultValue);
class Provider extends Component {
static contextType = Context;

constructor(props) {
super(props);
this.state =
typeof defaultValue === 'function'
? defaultValue()
: defaultValue || {};
}

componentWillMount() {
const { TAO } = this.context;
const trigrams = cleanInput(normalizeAC(tao));
const permutations = cartesian(trigrams);
permutations.forEach(trigram =>
TAO.addInlineHandler(trigram, this.contextHandler)
);
}

componentWillUnmount() {
const { TAO } = this.context;
const trigrams = cleanInput(normalizeAC(tao));
const permutations = cartesian(trigrams);
permutations.forEach(trigram =>
TAO.removeInlineHandler(trigram, this.contextHandler)
);
}

contextHandler = (tao, data) => {
const dataUpdate = handler
? handler(tao, data, data => this.setState(data))
: data;
if (dataUpdate instanceof AppCtx) {
return dataUpdate;
}
if (dataUpdate != null) {
const newState = Object.assign({}, this.state, dataUpdate);
this.setState(newState);
}
};

render() {
return (
<WrappingContext.Provider value={this.state}>
{this.props.children}
</WrappingContext.Provider>
);
}
}
return {
Provider,
Consumer: WrappingContext.Consumer
};
}
2 changes: 2 additions & 0 deletions packages/react-tao/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export { default as Provider } from './Provider';
export { default as DataHandler } from './DataHandler';
export { default as RenderHandler } from './RenderHandler';
export { default as SwitchHandler } from './SwitchHandler';
export { default as createContextHandler } from './createContextHandler';
export { default as withContext } from './withContext';
17 changes: 17 additions & 0 deletions packages/react-tao/src/withContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

import createContextHandler from './createContextHandler';

export default function withContext(tao, handler, defaultValue) {
if (typeof handler !== 'function') {
throw new Error('withContext `handler` must be a function');
}
const WrappingContext = createContextHandler(tao, handler, defaultValue);
return ComponentToWrap => props => (
<WrappingContext.Provider>
<WrappingContext.Consumer>
{value => <ComponentToWrap data={value} {...props} />}
</WrappingContext.Consumer>
</WrappingContext.Provider>
);
}

0 comments on commit b3a2827

Please sign in to comment.