Skip to content

Adding ShouldComponentUpdate life cycle #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 125 additions & 103 deletions integration/preact/component_v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,124 +5,146 @@
import { h, Component } from 'preact';
import getProps from '../util/getProps';

const isObject = (target) => (Object.prototype.toString.call(target) === '[object Object]');
const isObject = target =>
Object.prototype.toString.call(target) === '[object Object]';
let store = {};

function attachInstanceProps(instanceProps) {
this.instanceProps = instanceProps || {};
this.getInstanceProps = () => this.instanceProps;
this.setInstanceProps = (newVal) => {
if (!isObject(newVal)) {
return {};
}
const currentVal = this.instanceProps;
return (this.instanceProps = { ...currentVal, ...newVal });
};
this.instanceProps = instanceProps || {};
this.getInstanceProps = () => this.instanceProps;
this.setInstanceProps = newVal => {
if (!isObject(newVal)) {
return {};
}
const currentVal = this.instanceProps;
return (this.instanceProps = { ...currentVal, ...newVal });
};
}

function bindHandler(handlers, modifier) {
handlers && Object.keys(handlers).map((key) => {
const fn = handlers[key];
if (typeof fn === 'function') {
this[key] = modifier(fn, this);
}
handlers &&
Object.keys(handlers).map(key => {
const fn = handlers[key];
if (typeof fn === 'function') {
this[key] = modifier(fn, this);
}
});
}

export default function component(options = {}) {
const {
state,
template,
instanceProps,
componentDidMount,
componentWillUnmount,
componentWillReceiveProps,
...rest
} = options;
let { actions, watcher } = options;
return function wrapper(InnerComponent) {
return class Wrapper extends Component {
constructor(props, context = {}) {
super(props, context);
const setState = (newState) => this.setState({ ...newState });
const getState = () => this.state;
const _self = this;
this.state = state(props) || {};
this.__store__ = Wrapper.__store__;

if (this.__store__) {
watcher = this.__store__.watcher;
actions = this.__store__.actions;
}

const pluck = getProps(watcher);
const instancePropsClone = {...instanceProps}
// Attach handlers
bindHandler.call(this, actions, store.action);
bindHandler.call(this, rest, this.proxy);
attachInstanceProps.call(this, instancePropsClone);

let globalState = this.__store__ ? pluck(store ? store.getState() : {}) : {};

const updateStore = () => {
if (!this.__store__) {
return;
}
let localState = pluck(store ? store.getState() : {});
// if store value does change, do not call update
for (let i in localState) if (localState[i] !== globalState[i]) {
globalState = localState;
return this.setState(null);
}
// if above condition fails & store contains additional props
// update & cause re-render
for (let i in globalState) if (!(i in localState)) {
globalState = localState;
return this.setState(null);
}
};

this.mergeProps = () => ({
..._self,
...props,
setState,
getState,
...globalState
});

this.componentDidMount = () => {
if (this.__store__) {
store.subscribe(updateStore);
}
componentDidMount && componentDidMount.call(null, this.mergeProps());
}

this.componentWillUnmount = () => {
if (this.__store__) {
store.unsubscribe(updateStore);
}
componentWillUnmount && componentWillUnmount.call(null, this.mergeProps());
}

this.componentWillReceiveProps = (nxtProps) => {
componentWillReceiveProps && componentWillReceiveProps.call(null, nxtProps, this.mergeProps())
}

this.render = (props) => {
const view = template || InnerComponent;
return h(view, this.mergeProps());
};
}
const {
state,
template,
instanceProps,
componentDidMount,
componentWillUnmount,
componentWillReceiveProps,
shouldComponentUpdate,
...rest
} = options;
let { actions, watcher } = options;
return function wrapper(InnerComponent) {
return class Wrapper extends Component {
constructor(props, context = {}) {
super(props, context);
const setState = newState => this.setState({ ...newState });
const getState = () => this.state;
const _self = this;
this.state = state(props) || {};
this.__store__ = Wrapper.__store__;

if (this.__store__) {
watcher = this.__store__.watcher;
actions = this.__store__.actions;
}

proxy(func, context) {
return func && function hook() {
func.apply(null, [this.mergeProps(), ...arguments]);
}.bind(context);
const pluck = getProps(watcher);
const instancePropsClone = { ...instanceProps };
// Attach handlers
bindHandler.call(this, actions, store.action);
bindHandler.call(this, rest, this.proxy);
attachInstanceProps.call(this, instancePropsClone);

let globalState = this.__store__
? pluck(store ? store.getState() : {})
: {};

const updateStore = () => {
if (!this.__store__) {
return;
}
let localState = pluck(store ? store.getState() : {});
// if store value does change, do not call update
for (let i in localState)
if (localState[i] !== globalState[i]) {
globalState = localState;
return this.setState(null);
}
// if above condition fails & store contains additional props
// update & cause re-render
for (let i in globalState)
if (!(i in localState)) {
globalState = localState;
return this.setState(null);
}
};

this.mergeProps = () => ({
..._self,
...props,
setState,
getState,
...globalState
});

this.componentDidMount = () => {
if (this.__store__) {
store.subscribe(updateStore);
}
componentDidMount && componentDidMount.call(null, this.mergeProps());
};

this.componentWillUnmount = () => {
if (this.__store__) {
store.unsubscribe(updateStore);
}
componentWillUnmount &&
componentWillUnmount.call(null, this.mergeProps());
};

this.componentWillReceiveProps = nxtProps => {
componentWillReceiveProps &&
componentWillReceiveProps.call(null, nxtProps, this.mergeProps());
};

this.shouldComponentUpdate = nxtProps => {
if (shouldComponentUpdate) {
return shouldComponentUpdate.call(
null,
nxtProps,
this.mergeProps()
);
}
};

this.render = props => {
const view = template || InnerComponent;
return h(view, this.mergeProps());
};
}

proxy(func, context) {
return (
func &&
function hook() {
func.apply(null, [this.mergeProps(), ...arguments]);
}.bind(context)
);
}
};
};
}

export function injectStore(appStore) {
store = appStore;
store = appStore;
}