0.3.0 • Published 9 months ago
templates-for-react v0.3.0
templates_for_react
It's a small cli to help the creation of react component or xstate machine.
Installation
npm install templates_for_react -g
Usage
cft
1. Is your version of react >= 18 ? (y/N)
2. Please choose which template to use
* Component
* ComponentWithStorybook
* Context
* Function
* Hook
* StoreZustand
* Machine
* AssignXstate
* GuardXstate
* useMutation
* useQuery
3. Please write a name
4. Select a target directory for your component
Templates Available
Context
Structure Context
[Name]
|--[Name]Provider.tsx
|--use[Name]Context.ts
|--index.ts
Details Context
- NameProvider.tsx
import * as React from "react";
export interface [Name]ContextProps { }
export const [Name] = React.createContext<[Name]ContextProps>({});
export const [Name]Provider = ({ children }: PropsWithChildren<[Name]ContextProps>) => {
return <[Name].Provider value={{}}>{children}</[Name].Provider>;
};
- useNameContext.ts
import * as React from "react";
import { [Name] } from "./[Name]Provider";
export const use[Name]Context = () => {
const context = React.useContext([Name]);
// Uncomment if your context doesn't have reasonable defaults
// if (context === undefined) {
// throw new Error(
// "use[Name]Context must be used within a [Name]Provider"
// );
// }
return context;
};
- index.ts
export { [Name]Provider } from "./[Name]Provider";
export { use[Name]Context } from "./use[Name]Context";
ComponentStory
Structure ComponentStory
[Name]
|--[Name].spec.tsx
|--[Name].stories.tsx
|--[Name].tsx
|--index.ts
Details ComponentStory
- Name.spec.tsx
import * as React from 'react';
import { render, screen } from '@testing-library/react';
import [Name], { [Name]Props } from './[Name]';
describe('<[Name] />', () => {
it('should render', () => {
const { container } = render(<[Name] />);
expect(container).toBeInTheDocument();
});
});
- Name.stories.tsx
import * as React from 'react';
import { Meta, Story } from '@storybook/react';
import [Name], { [Name]Props } from './[Name]';
export default {
title: "/[Name]",
component: [Name],
} as Meta;
const Template: Story<[Name]Props> = (args) => {
return <[Name] {...args} />;
};
export const Default = Template.bind({});
- Name.tsx
import * as React from 'react';
export interface [Name]Props {}
const [Name]: React.FC<[Name]Props> = ({}) => {
return <div>[Name]</div>
};
- index.ts
export { [Name] } from "./[Name]";
Component
Structure Component
[Name]
|--[Name].spec.tsx
|--[Name].tsx
Details Component
- Name.spec.tsx
import * as React from 'react';
import { cleanup, render, screen } from '@testing-library/react';
import { [Name] } from '../[Name]';
describe('[Name]', () => {
afterEach(() => {
cleanup();
});
it('should render [Name]', () => {
// Given
// When
const { container } = render(<[Name] />);
//Then
expect(container).toBeInTheDocument();
});
});
- Name.tsx
import * as React from 'react';
export interface [Name]Props {
}
export const [Name]: React.FC<[Name]Props> = () => {
return (
<div>
[Name]
</div>
);
};
[Name].displayName = '[Name]';
Function
Structure Function
[Name]
|--[Name].spec.ts
|--[Name].ts
Details Function
- Name.spec.ts
import { [Name] } from "./[Name]";
describe('[Name]', () => {
it('should ', () => {
});
});
- Name.ts
export const [Name] = () => {
};
Hook
Structure Hook
use[Name]
|--use[Name].spec.tsx
|--use[Name].tsx
Details Hook
- useName.tsx
import * as React from "react";
export const use[Name] = () => {
return () => {
return 2;
};
};
- useName.spec.tsx
import { renderHook } from '@testing-library/react-hooks';
import { [Name] } from './[Name]';
describe('[Name]', () => {
it('should return 2', () => {
const { result } = renderHook(() => [Name]());
const value = result.current();
expect(value).toEqual(2);
});
});
__
StoreZustand
Structure StoreZustand
[Name]
|--action
|--index.ts
|--setIndex.tsx
|--use[Name].tsx
Details StoreZustand
- useName.tsx
import create, { StoreApi } from "zustand";
import { setIndex } from "./actions";
interface [Name]State {
index: number;
};
interface [Name]Actions {
setIndex: (value: number) => void;
};
const initialState: [Name]State = {
index: 0,
}
export type [Name]StoreType = [Name]State & [Name]Actions;
export type Set[Name]Store = StoreApi<[Name]StoreType>["setState"];
export type Get[Name]Store = StoreApi<[Name]StoreType>["getState"];
export const use[Name]Store = create<[Name]State & [Name]Actions>(set => ({
...initialState,
setIndex: setIndex(set)
}))
- action/setIndex.ts
import { Set[Name]Store } from "../use[Name]Store";
export const setIndex = (set: Set[Name]Store) => (value: number) =>
set(_state => ({
index: value
}));
- action/index.ts
export { setIndex } from "./setIndex";
__
useMutation Hooks
Structure useMutation Hooks
[Name]
|--[Name].spec.tsx
|--[Name].tsx
|--index.tsx
Details useMutation Hooks
- --Name.spec.tsx
import * as React from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from 'react-query';
const renderWithClient = (client: QueryClient, ui: React.ReactElement) => {
const { rerender, ...result } = render(
<QueryClientProvider client={client}>{ui}</QueryClientProvider>
);
return {
...result,
rerender: (rerenderUi: React.ReactElement) =>
rerender(
<QueryClientProvider client={client}>
{rerenderUi}
</QueryClientProvider>
),
};
};
describe('use[Name]', () => {
const queryCache = new QueryCache();
const mutationCache = new MutationCache();
const queryClient = new QueryClient({ queryCache, mutationCache });
it("should ", async () => {
function Page() {
const { mutate, data = { label: "" } } = use[Name]();
return (
<div>
<h1 data-testid="title">{data["label"]}</h1>
<button onClick={() => mutate()}>mutate</button>
</div>
);
}
const { getByTestId, getByText } = renderWithClient(queryClient, <Page />);
expect(getByTestId("title").textContent).toBe("");
fireEvent.click(getByText("mutate"));
await waitFor(() => getByTestId("title"));
expect(getByTestId("title").textContent).toBe();
});
});
- --Name.tsx
import { useMutation } from 'react-query';
const [Name] = () => useMutation(() => {
// return fetch("/api/data") as json
return "Hello";
}, {
onMutate: variables => {
// A mutation is about to happen!
// Optionally return a context containing data to use when for example rolling back
},
onError: (error, variables, context) => {
// An error happened!
console.log(`rolling back optimistic update with id ${context}`)
},
onSuccess: (data, variables, context) => {
// Boom baby!
},
onSettled: (data, error, variables, context) => {
// Error or success... doesn't matter!
},
});
export default [Name];
- --index.tsx
export { default } from './[Name]';
useQuery Hooks
Structure useQuery Hooks
[Name]
|--[Name].spec.tsx
|--[Name].tsx
|--index.tsx
Details useQuery Hooks
- --Name.spec.tsx
import { QueryClient, QueryClientProvider } from 'react-query';
import { renderHook } from '@testing-library/react-hooks';
import { [Name] } from './[Name]';
const queryClient = new QueryClient();
const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
describe('[Name]', () => {
it('should ', async () => {
const { result, waitFor } = renderHook(() => [Name](), { wrapper });
await waitFor(() => result.current.isSuccess);
expect(result.current.data).toEqual("Hello");
});
});
- --Name.tsx
import { useQuery } from 'react-query';
const [Name] = () => {
return useQuery("queryHooks", () => {
// return fetch("/api/data") as json
return "Hello";
});
};
export default [Name];
- --index.tsx
export { default } from './[Name]';
Machine XState
Structure Machine XState
[Name]
|--actions
|--actionExample.spec.ts
|--actionExample.ts
|--guards
|--guardExample.spec.ts
|--guardExample.ts
|--services
|--types
|--index.ts
|--[Name]Machine.ts
Details Machine XState
- --actions > actionExample.spec.ts
- --actions > actionExample.ts
- --guards > guardExample.spec.ts
- --actions > guardExample.ts
- --types > index.ts
- --NameMachine.ts
__
Action Assign XState
Structure Action Assign XState
[Name]Assign
|--[Name]Assign.spec.ts
|--[Name]Assign.ts
Details Action Assign XState
- NameAssign.spec.ts
import { TimerContext } from '../../types';
import { ActionTypes } from "xstate";
import { [Name]Assign, [Name]Assignment } from "./assign[Name]";
describe('assign[Name]', () => {
it('should return object', () => {
const result = assign[Name];
expect(result.type).toEqual(ActionTypes.Assign);
});
it('should return assignement', () => {
const context: Context = {
}
const newContext = assignment[Name](context, { type: ''});
expect(newContext.).toEqual();
});
});
- NameAssign.ts
import { ActionTypes, AssignAction } from "xstate";
export const [Name]Assignment = (context: Context, event: Event): Partial<Context> => {
return {
elapsed: event.value
};
}
export const [Name]Assign : AssignAction<Context, Event> = {
type: ActionTypes.Assign,
assignment: [Name]Assignment
}
__