Commit 71c634b8 authored by Sendya's avatar Sendya

feat: createContext, useContext

parent 86e775e5
import { createApp, defineComponent, inject, reactive, watchEffect } from 'vue'; import { createApp, defineComponent, ref, reactive, toRaw, onMounted } from 'vue';
import { Card, Space, Button, Tag } from 'ant-design-vue'; import { Card, Space, Button, Tag } from 'ant-design-vue';
import { useContext, createContext } from '../src/RouteContext'; import { createRouteContext, useRouteContext } from '../src/RouteContext';
import 'ant-design-vue/dist/antd.less'; import 'ant-design-vue/dist/antd.less';
const DemoComponent = { const DemoComponent = {
setup() { setup() {
const jsonEditorRef = ref(null);
const state = reactive({ const state = reactive({
name: 'value', name: 'value',
}); });
const { state: routeContext, provider: RouteContextProvider } = createContext({ const {
hasSiderMenu: true, state: routeContext,
provider: RouteContextProvider
} = createRouteContext({
hasSideMenu: true,
collapsed: true, collapsed: true,
isMobile: false, isMobile: false,
menuData: [] menuData: []
});
onMounted(() => {
console.log('jsonEditorRef', jsonEditorRef)
}) })
return () => ( return () => (
...@@ -38,10 +46,11 @@ const DemoComponent = { ...@@ -38,10 +46,11 @@ const DemoComponent = {
> >
Change Value Change Value
</Button> </Button>
</Space> </Space>
<div style={{ margin: '12px 0' }}> <div style={{ margin: '12px 0' }}>
<p>state.name: { JSON.stringify(state.name) }</p> <p>state.name: { JSON.stringify(state.name) }</p>
routeContext:
<pre>{ JSON.stringify(routeContext, null, 4) }</pre>
</div> </div>
</Card> </Card>
<div class="demo" style="background: rgb(244,244,244);"> <div class="demo" style="background: rgb(244,244,244);">
...@@ -56,14 +65,17 @@ const DemoComponent = { ...@@ -56,14 +65,17 @@ const DemoComponent = {
const TestChildComponent = defineComponent({ const TestChildComponent = defineComponent({
setup () { setup () {
const routeContext = useContext(); const routeContext = useRouteContext();
console.log('TestChildComponent.routeContext', routeContext) console.log('TestChildComponent.routeContext', routeContext)
return () => { return () => {
const { menuData, collapsed } = routeContext const { menuData, collapsed } = routeContext
return ( return (
<div class="test-child-component"> <div class="test-child-component">
menuData: {JSON.stringify(menuData)} menuData:
<pre>
{JSON.stringify(menuData, null, 4)}
</pre>
<p> <p>
collapsed: {collapsed.toString()} collapsed: {collapsed.toString()}
</p> </p>
......
import { defineComponent, h, reactive, provide, inject, toRefs, UnwrapRef, PropType, SetupContext, InjectionKey, VNode, RendererNode, RendererElement } from 'vue'; import { InjectionKey } from 'vue';
import { createContext, useContext } from './hooks/context';
import { RouteProps } from './typings';
import { PureSettings } from './defaultSettings'; import { PureSettings } from './defaultSettings';
export interface RouteContextProps extends Partial<PureSettings> { export interface RouteContextProps extends Partial<PureSettings> {
...@@ -9,97 +8,17 @@ export interface RouteContextProps extends Partial<PureSettings> { ...@@ -9,97 +8,17 @@ export interface RouteContextProps extends Partial<PureSettings> {
isMobile?: boolean; isMobile?: boolean;
prefixCls?: string; prefixCls?: string;
collapsed?: boolean; collapsed?: boolean;
hasSiderMenu?: boolean; hasSideMenu?: boolean;
hasHeader?: boolean; hasHeader?: boolean;
siderWidth?: number; sideWidth?: number;
hasFooterToolbar?: boolean; hasFooterToolbar?: boolean;
hasFooter?: boolean; hasFooter?: boolean;
setHasFooterToolbar?: (bool: boolean) => void; setHasFooterToolbar?: (bool: boolean) => void;
} }
export const routeContextProps = { const routeContextInjectKey: InjectionKey<RouteContextProps> = Symbol();
isMobile: {
type: Boolean,
default: false,
},
menuData: {
type: Object as PropType<RouteProps[]>,
default: undefined,
},
prefixCls: {
type: String,
default: 'ant-pro',
},
collapsed: {
type: Boolean,
},
hasSiderMenu: {
type: Boolean,
},
siderWidth: {
type: Number,
},
hasFooterToolbar: {
type: Boolean,
},
hasFooter: {
type: Boolean,
},
setHasFooterToolbar: {
type: Function as PropType<(bool: boolean) => void>,
},
};
export const defaultRouteContext: RouteContextProps = {
};
export const contextKey: InjectionKey<RouteContextProps> = Symbol();
export const useContext = () => {
return inject(contextKey, defaultRouteContext);
};
export const RouteContextProvider = defineComponent({
name: 'RouteContextProvider',
props: routeContextProps,
setup(props, { slots }: SetupContext) {
// const route = useRoute();
// if (route === undefined) {
// console.info('route not used')
// }
// const route = useRoute();
const routeContext = reactive({
...toRefs(props),
// ...toRefs(route),
});
provide(contextKey, routeContext);
return () => slots.default && slots.default(); export const createRouteContext = (context: RouteContextProps) =>
}, createContext<RouteContextProps>(context, routeContextInjectKey);
});
export interface IRouteContext<T> {
provider: (props: any, ctx: any) => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>
state: UnwrapRef<T> | T;
}
export const createContext = (context: RouteContextProps): IRouteContext<RouteContextProps> => {
const state = reactive<RouteContextProps>({
...context,
});
const Provider = (_, ctx) => {
return h(RouteContextProvider, state, ctx.slots)
}
return {
provider: Provider,
state,
};
}
export default RouteContextProvider; export const useRouteContext = () => useContext<RouteContextProps>(routeContextInjectKey);
import {
defineComponent,
h,
InjectionKey,
provide,
inject,
reactive,
RendererElement,
RendererNode,
SetupContext,
toRefs,
UnwrapRef,
VNode,
PropType,
DefineComponent,
} from 'vue';
export type ContextType<T> = any;
// VNode<RendererNode, RendererElement, {
// [key: string]: any;
// }>
/**
(props: any, ctx: SetupContext) => DefineComponent<{}, () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>>;
*/
export interface CreateContext<T> {
provider: DefineComponent<{}, () => VNode | VNode[]>;
state: UnwrapRef<T> | T;
}
const RouteContextProvider = defineComponent({
name: 'RouteContextProvider',
inheritAttrs: false,
props: {
contextInjectKey: {
type: [Object, String, Symbol] as PropType<InjectionKey<any>>,
required: true,
},
},
setup(props, { slots, attrs }: SetupContext) {
console.log('props', props, attrs);
const context = reactive({
...attrs,
});
provide(props.contextInjectKey, context);
return () => slots.default();
},
});
export const createContext = <T>(context: ContextType<T>,
contextInjectKey: InjectionKey<ContextType<T>> = Symbol()
): CreateContext<T> => {
const state = reactive<ContextType<T>>({
...context,
});
const ContextProvider = defineComponent( {
name: 'ContextProvider',
inheritAttrs: false,
setup(props, { slots }: SetupContext) {
provide(contextInjectKey, state);
return () => slots.default();
},
})
return {
state,
provider: ContextProvider,
};
};
export const useContext = <T>(contextInjectKey: InjectionKey<ContextType<T>> = Symbol(), defaultValue?: ContextType<T>): T => {
return inject(contextInjectKey, defaultValue || {} as T)
}
// :: examples ::
//
// interface MyContextProps {
// param1: string;
// param2: boolean;
// someData?: string[];
// }
//
// const { state, provider } = createContext<MyContextProps>({
// param1: 'abc',
// param2: false,
// someData: ['a', 'b', 'c', 'd']
// });
//
// const value = useContext<MyContextProps>();
//
// console.log('value', toRaw(value));
// console.log('param1', value.param1); // 'abc'
// console.log('param2', value.param2); // false
// console.log('someData', value.someData); // ['a', 'b', 'c', 'd']
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment