Skip to content

Commit 7e2ae75

Browse files
committed
feat(React Context): Add HOC for button
- Add a sample Login Form template component - Create an HOC provider component to access parent component context within child
1 parent 8e6a0fa commit 7e2ae75

File tree

4 files changed

+116
-3
lines changed

4 files changed

+116
-3
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React, { createContext } from 'react';
2+
3+
const data = {} as any;
4+
export const DataContext = createContext(data);
5+
6+
export const withDataContext = <P extends object>(Component: React.ComponentType<P>) => {
7+
return function fn(props: P) {
8+
return (
9+
<DataContext.Consumer>
10+
{
11+
(context) => <Component
12+
{...props}
13+
context={context}
14+
/>
15+
}
16+
</DataContext.Consumer>
17+
);
18+
};
19+
};

src/components/elements/Button/index.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,36 @@ import {
66

77
import 'antd/lib/button/style/css';
88

9-
export interface ButtonProps extends AntButtonProps {
9+
import { withDataContext } from '../../contexts/withDataContext';
10+
11+
interface ButtonStateProps extends AntButtonProps {
1012
label: string;
13+
context?: any;
14+
}
15+
16+
export interface ButtonActionProps {
17+
customCallback?: (data: any) => void;
1118
}
1219

20+
export type ButtonProps = ButtonStateProps & ButtonActionProps
21+
1322
function Button(props: ButtonProps) {
14-
const {label, ...rest} = props;
23+
const { label, context, onClick, customCallback, ...rest } = props;
24+
25+
function handleClick(e: React.MouseEvent) {
26+
customCallback && customCallback(context);
27+
}
1528

1629
return (
1730
<AntButton
1831
{...rest}
32+
onClick={handleClick}
1933
>
2034
{props.label}
2135
</AntButton>
2236
)
2337
}
2438

25-
export default Button;
39+
export default Button;
40+
41+
export const ButtonWithContext = withDataContext(Button)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { action } from '@storybook/addon-actions';
2+
import { Story } from '@storybook/react/types-6-0';
3+
4+
import LoginForm, { LoginFormProps } from './index';
5+
6+
export default {
7+
title: 'Components/Templates/Login Form',
8+
component: LoginForm,
9+
// argTypes: {
10+
// type: {
11+
// control: {
12+
// type: 'select',
13+
// options: [
14+
// "default",
15+
// "primary",
16+
// "ghost",
17+
// "dashed",
18+
// ],
19+
// },
20+
// },
21+
// },
22+
};
23+
24+
const Template: Story<LoginFormProps> = (args) => <LoginForm {...args} />;
25+
26+
export const Default = Template.bind({});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { useState, useEffect, createContext } from 'react';
2+
import { DataContext } from '../../contexts/withDataContext';
3+
import Button, {ButtonWithContext} from '../../elements/Button';
4+
5+
import Input from '../../elements/Input';
6+
7+
import Card from '../../widgets/Card';
8+
9+
export interface LoginFormProps {
10+
11+
}
12+
13+
const data = {
14+
page: "Login page",
15+
company: "My company",
16+
}
17+
18+
function LoginForm(props: LoginFormProps) {
19+
function getContext (data: any) {
20+
// console.log(data);
21+
}
22+
23+
return (
24+
<DataContext.Provider value={data}>
25+
<Card
26+
title="Login"
27+
actions={[
28+
<ButtonWithContext
29+
type="primary"
30+
label="Login"
31+
customCallback={getContext}
32+
/>,
33+
<Button
34+
type="ghost"
35+
label="Sign Up"
36+
/>
37+
]}>
38+
<Input
39+
type="text"
40+
placeholder="email"
41+
/>
42+
<Input
43+
type="password"
44+
placeholder="password"
45+
/>
46+
</Card>
47+
</DataContext.Provider>
48+
49+
)
50+
}
51+
52+
export default LoginForm;

0 commit comments

Comments
 (0)