Skip to content
This repository has been archived by the owner on Aug 16, 2023. It is now read-only.

Commit

Permalink
feat: add context
Browse files Browse the repository at this point in the history
  • Loading branch information
zeromake committed Feb 11, 2018
1 parent 20319f4 commit dc29e67
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 42 deletions.
2 changes: 0 additions & 2 deletions src/component.ts
Expand Up @@ -256,7 +256,5 @@ export class Component <PropsType extends IBaseProps, StateType extends IKeyValu
* @param context
*/
public render(props: PropsType, state: StateType, context: IKeyValue): childType {
// console.error("not set render");
return null;
}
}
1 change: 1 addition & 0 deletions src/create-context.ts
Expand Up @@ -12,6 +12,7 @@ export function createContext<T>(defaultValue: T, calculateChangedBits?: ((a: T,
defaultValue,
currentValue: defaultValue,
changedBits: 0,
ConsumerChildren: [],
Provider: null as any,
Consumer: null as any,
};
Expand Down
5 changes: 3 additions & 2 deletions src/types.ts
Expand Up @@ -20,7 +20,7 @@ export type funComponent = (props?: IBaseProps, content?: any) => childType;
/**
* nodeName的类型
*/
export type childType = VNode|string|number|boolean|null|undefined;
export type childType = VNode|string|number|boolean|null|undefined|void;

export type ComponentContext = Component<any, any> | Element | Node | HTMLElement | IVDom;

Expand All @@ -37,6 +37,7 @@ export interface IReactContext<T> extends IBaseVNode {
defaultValue: T;
currentValue: T;
changedBits: number;
ConsumerChildren: any[];
Provider: IReactProvider<T>;
Consumer: IReactContext<T>;
}
Expand All @@ -45,4 +46,4 @@ export interface IReactProvider<T> extends IBaseVNode {
context: IReactContext<T>;
}

export type NodeName = string | typeof Component | funComponent | IReactContext<any> | IReactContext<any>;
export type NodeName = string | typeof Component | funComponent | IReactContext<any> | IReactProvider<any>;
17 changes: 14 additions & 3 deletions src/vdom/component-recycler.ts
@@ -1,5 +1,6 @@
import { Component } from "../component";
import { IKeyValue } from "../types";
import { IKeyValue, IReactContext, IReactProvider} from "../types";

// import { h } from "../h";

/**
Expand Down Expand Up @@ -33,12 +34,22 @@ export function collectComponent(component: Component<IKeyValue, IKeyValue>) {
* @param props
* @param context
*/
export function createComponent(Ctor: any, props: IKeyValue, context: IKeyValue, component: Component<IKeyValue, IKeyValue> | undefined | void | null): Component<IKeyValue, IKeyValue> {
export function createComponent(
Ctor: any,
props: IKeyValue,
context: IKeyValue,
component: Component<IKeyValue, IKeyValue> | undefined | void | null,
newContext?: IReactContext<any>| IReactProvider<any>,
): Component<IKeyValue, IKeyValue> {
const list = components[Ctor.name];
let inst: Component<IKeyValue, IKeyValue>;
// 创建组件实例
if (Ctor.prototype && Ctor.prototype.render) {
inst = new Ctor(props, context);
if (newContext) {
inst = new Ctor(props, context, newContext);
} else {
inst = new Ctor(props, context);
}
Component.call(inst, props, context);
} else {
// 一个方法
Expand Down
5 changes: 3 additions & 2 deletions src/vdom/component.ts
Expand Up @@ -6,7 +6,7 @@ import { createComponent, collectComponent } from "./component-recycler";
import { getNodeProps, setRef } from "./index";
import { removeNode } from "../dom/index";
import { extend } from "../util";
import { IKeyValue, childType } from "../types";
import { IKeyValue, childType, IReactContext, IReactProvider } from "../types";
import { IVDom } from "./index";
import { findVDom, setVDom, findVoidNode, setVoidNode } from "../find";
import {
Expand Down Expand Up @@ -340,6 +340,7 @@ export function buildComponentFromVNode(
vnode: VNode,
context: IKeyValue,
mountALL: boolean,
newContext?: IReactContext<any>| IReactProvider<any>,
): IVDom {
// 获取根组件缓存
let c = vdom && vdom.component;
Expand Down Expand Up @@ -367,7 +368,7 @@ export function buildComponentFromVNode(
vdom = oldVDom = null;
}
// 通过缓存组件的方式创建组件实例
c = createComponent(vnode.nodeName, props, context, vnode.component);
c = createComponent(vnode.nodeName, props, context, vnode.component, newContext);
if (vdom && !c._nextVDom) {
// 上次这个标签为原生组件,把将要卸载的组件dom缓存
c._nextVDom = vdom;
Expand Down
21 changes: 21 additions & 0 deletions src/vdom/context-consumer.ts
@@ -0,0 +1,21 @@
import { Component } from "../component";
import { IBaseProps, IReactContext } from "../types";

// console.log(Component);
export default function buildConsumer(ComponentIMP: typeof Component) {
class Consumer extends ComponentIMP<IBaseProps, any> {
private _context: IReactContext<any>;
constructor(p: any, c: any, context: IReactContext<any>) {
super(p, c);
this._context = context;
context.ConsumerChildren.push(this);
}
public componentWillUnmount() {
this._context.ConsumerChildren = this._context.ConsumerChildren.filter((i: any) => i !== this);
}
public render() {
return this.props.children(this._context.currentValue);
}
}
return Consumer;
}
33 changes: 33 additions & 0 deletions src/vdom/context-provider.ts
@@ -0,0 +1,33 @@
import { Component } from "../component";
import { IBaseProps, IReactProvider } from "../types";

interface IProps extends IBaseProps {
value: any;
}
export default function buildProvider(ComponentIMP: typeof Component) {
class Provider extends ComponentIMP<IProps, any> {
private _context: any;
constructor(p: IProps, c: any, context: IReactProvider<any>) {
super(p, c);
this._context = context;
this._context.context.currentValue = p.value;
}
public componentDidUpdate(previousProps: IProps) {
if (this._context.context.calculateChangedBits) {
if (this._context.context.calculateChangedBits(this._context.context.currentValue, this.props.value)) {
this._context.context.currentValue = this.props.value;
this._context.context.changedBits += 1;
this._context.context.ConsumerChildren.forEach((child: any) => {
if (child) {
child.setState({});
}
});
}
}
}
public render() {
return this.props.children;
}
}
return Provider;
}
7 changes: 7 additions & 0 deletions src/vdom/context.ts
@@ -0,0 +1,7 @@
import buildConsumer from "./context-consumer";
import buildProvider from "./context-provider";

export {
buildConsumer,
buildProvider,
};
26 changes: 20 additions & 6 deletions src/vdom/diff.ts
Expand Up @@ -3,7 +3,7 @@ import options from "../options";
import { isSameNodeType, isNamedNode } from "./index";
import { VNode } from "../vnode";
import { Component } from "../component";
import { IKeyValue, childType } from "../types";
import { IKeyValue, childType, IBaseVNode, IReactContext, IReactProvider } from "../types";
import { IVDom, buildVDom, setRef } from "./index";
import {
buildComponentFromVNode,
Expand All @@ -19,8 +19,12 @@ import {
} from "../dom/index";
import { findVDom, setVDom, findVoidNode, setVoidNode } from "../find";
import { innerHTML , isArray, REACT_CONTEXT_TYPE, REACT_PROVIDER_TYPE } from "../util";
import { buildConsumer, buildProvider } from "./context";

export const mounts: Array<Component<any, any>> = [];
let Consumer: any = null;
let Provider: any = null;

export const mounts: any[] = [];

export let diffLevel = 0;

Expand Down Expand Up @@ -164,10 +168,20 @@ function idiff(
if (typeof vnodeName === "function") {
// 是一个组件,创建或复用组件实例,返回dom
return buildComponentFromVNode(vdom, (vnode as VNode), context, mountAll); // , (vnode as VNode).component);
} else if (vnodeName === REACT_CONTEXT_TYPE) {
return VOID_NODE;
} else if (vnodeName === REACT_PROVIDER_TYPE) {
return VOID_NODE;
} else if (vnodeName && (vnodeName as IBaseVNode).$$typeof === REACT_CONTEXT_TYPE) {
if (Consumer === null) {
Consumer = buildConsumer(Component);
}
(vnode as any).nodeName = Consumer;
return buildComponentFromVNode(vdom, (vnode as VNode), context, mountAll, vnodeName as IReactContext<any>);
// return VOID_NODE;
} else if (vnodeName && (vnodeName as IBaseVNode).$$typeof === REACT_PROVIDER_TYPE) {
if (Provider === null) {
Provider = buildProvider(Component);
}
(vnode as any).nodeName = Provider;
return buildComponentFromVNode(vdom, (vnode as VNode), context, mountAll, vnodeName as IReactProvider<any>);
// return VOID_NODE;
}
// 重新判断一下是否要创建svg
isSvgMode = vnodeName === "svg"
Expand Down
2 changes: 2 additions & 0 deletions src/zreact.ts
Expand Up @@ -58,6 +58,7 @@ export default {
cloneElement,
createClass,
createPortal,
createContext,
findDOMNode,
findVDom,
isValidElement,
Expand All @@ -80,6 +81,7 @@ export {
createClass,
createElement,
createPortal,
createContext,
findDOMNode,
findVDom,
isValidElement,
Expand Down
104 changes: 77 additions & 27 deletions test/test.html
Expand Up @@ -16,43 +16,93 @@
var h = zreact.h;
var render = zreact.render;
var Component = zreact.Component;
class Foo extends Component {
componentDidMount() {
console.log("Foo componentDidMount")
}
componentWillUnmount() {
console.log("Foo componentWillUnmount")
}
render() {
return h("h1", null, "测试")
}
}
class Bar extends Component {
componentDidMount() {
console.log("Bar componentDidMount")
}
componentWillUnmount() {
console.log("Bar componentWillUnmount")
}
const ThemeContext = zreact.createContext({
background: 'red',
color: 'white'
});
const ContextMap = {
1: { background: 'red', color: 'white' },
2: { background: 'green', color: 'white' }
}
class App extends Component {
constructor() {
super()
this.state = {
child: Foo
map: 1
}
this.test = this.test.bind(this)
}
test() {
this.setState({
child: this.state.child === Bar ? Foo : Bar
});
render () {
return (
h("div", null,
h(ThemeContext.Provider, {value: ContextMap[this.state.map]},
h(Header)
),
h("button", {onClick: () => this.setState({
map: this.state.map === 1 ? 2: 1
})}, "测试")
)

);
}
}
class Header extends Component {
shouldComponentUpdate() {
return false
}
render() {
return h("div", null, h('button', {onClick: this.test}, "切换"), h(this.state.child))
render () {
return h(Title, null, "Hello React Context API")
}
}
class Title extends Component {
render () {
return h(ThemeContext.Consumer, null,
context => h("h1", {style: {background: context.background, color: context.color}},
this.props.children
)
);
}
}
var dom = render(h(App), document.getElementById('app'))
render(
h(App),
document.getElementById('app')
);
// class Foo extends Component {
// componentDidMount() {
// console.log("Foo componentDidMount")
// }
// componentWillUnmount() {
// console.log("Foo componentWillUnmount")
// }
// render() {
// return h("h1", null, "测试")
// }
// }
// class Bar extends Component {
// componentDidMount() {
// console.log("Bar componentDidMount")
// }
// componentWillUnmount() {
// console.log("Bar componentWillUnmount")
// }
// }
// class App extends Component {
// constructor() {
// super()
// this.state = {
// child: Foo
// }
// this.test = this.test.bind(this)
// }
// test() {
// this.setState({
// child: this.state.child === Bar ? Foo : Bar
// });
// }
// render() {
// return h("div", null, h('button', {onClick: this.test}, "切换"), h(this.state.child))
// }
// }
// var dom = render(h(App), document.getElementById('app'))
// render(h("div"), document.getElementById('app'), dom)
// render(h(Bar), document.getElementById('app'))

Expand Down

0 comments on commit dc29e67

Please sign in to comment.