Skip to content

Latest commit

 

History

History
657 lines (484 loc) · 16 KB

CREATING_FILES.md

File metadata and controls

657 lines (484 loc) · 16 KB

Creating Files

rhc provide you more flexibility and easy to use approach to create your files and folders for your componets, pages and redux implementation.

  • By default rhc create files with the project's language, so if the project is written in TypeScript all the created files will be in TypeScript, and the same applies for JavaScript.

  • If you want to force the use of a specific language you can add the --js or --ts options at the end of your create commands.

  • rhc will not overwrite the existed implementation for all of the create commands.

The following points shows how to use the create command.

Components

  1. To create your components simply run:
rhc create -c <component-name>
  • This will create a component named after the given name <component-name> under the src/components/<component-name>/ folder.

Example

rhc create -c test-component
  • This command will create the following directory src/components/test-component/:
src
└───components
    └───test-component
            index.jsx
            styles.css
  • Where index.jsx represents the React FC component that contains the following:
import "./styles.css";

const TestComponent = () => {
  return <div>TestComponent component created!</div>;
};
export default TestComponent;
  • And for the styles.css you will see:
/* TestComponent styles */
  1. To create multiple components simply run:
rhc create -c <component-name-1> <component-name-2> ...
  • This will create multiple components for the given names under the src/components/ folder.

Exmaple

rhc create -c comp-1 comp-2
  • This command will create under the src/components/ folder the following:
src
└───components
    ├───comp-1
    │       index.jsx
    │       styles.css
    │
    └───comp-2
            index.jsx
            styles.css
  1. To create one or mutliple components in a specified path that resides under the src/components/ folder, simply run:
rhc create -c <component-name-1> <component-name-2> ... -f <folder-path>
  • This will create your components under the src/components/<folder-path>/ folder.

Example

rhc create -c comp-1 comp-2 -f foo/bar
  • This command will create under the src/components/ folder the following:
src
└───components
    └───foo
        └───bar
            ├───comp-1
            │       index.jsx
            │       styles.css
            │
            └───comp-2
                    index.jsx
                    styles.css

Pages

  1. To create your page simply run:
rhc create -p <page-name>
  • This will create a page after the given name page-name under the src/pages/ folder.

Example

rhc create -p test-page
  • This will create the following:
src
pages
    └───test-page
        │   index.jsx
        │   styles.css
        │
        └───functions
                index.js
  • Where index.jsx represent the page which is nothing but a React FC component that contains the following:
import "./styles.css";

const TestPage = () => {
  return <div>TestPage page created!</div>;
};
export default TestPage;
  • As for styles.css you will find:
/* TestPage styles */
  • And under the functions folder you should write your page's functions and export them in function/index.js file, which by default it will contain the following:
// write your TestPage functions here
  1. To create multiple pages simply run:
rhc create -p <page-name-1> <page-name-2> ...
  • This will create multiple pages under the src/pages/ folder.

Example

rhc create -p page-1 page-2
  • This will create the following:
src
pages
    ├───page-1
    │   │   index.jsx
    │   │   styles.css
    │   │
    │   └───functions
    │           index.js
    │
    └───page-2
        │   index.jsx
        │   styles.css
        │
        └───functions
                index.js
  1. To create one or multiple pages in a specific path that resides under src/pages/ folder, simply run:
rhc create -p <page-name-1> <page-name-2> ... -f <folder-path>
  • This will create your pages under the src/pages/<folder-path> folder.

Example

rhc create -p page-1 page-2 -f foo/bar
  • This will create the following:
src
└───pages
    └───foo
        └───bar
            ├───page-1
            │   │   index.jsx
            │   │   styles.css
            │   │
            │   └───functions
            │           index.js
            │
            └───page-2
                │   index.jsx
                │   styles.css
                │
                └───functions
                        index.js

Templates

You can create your pages and components with your defined templates by following these steps:

  1. First thing to do is to create a .template folder at the root of your react project.

  2. Inside the .template folder you can add your template, for example componentWithUseEffect.tsx (the file extension doesn't matter so it could be *.jsx, *.js or *.tsx):

export default function __COMPONENT__() {
  useEffect(() => {}, []);

  return (
    <div>
      <h1>Hello, World!</h1>
    </div>
  );
}
  • There is a restriction in naming these templates which is you should not put dots (.) between the name, like this (component.WithUseEffect.jsx). It should only contain one dot that makes the extension file like we're doing above.

  • You should type __COMPONENT__ in the template file and it will be replaced with the component name you want to create.

  1. After creating your template you can use them to create components or pages as the following:
rhc create -c <component-name> -t <template-name>
rhc create -p <page-name> -t <template-name>
  • And of course, you can create multiple components or pages with the same template.

Example

As for our example it can be used like this for the above template:

rhc create -c comp -t componentWithUseEffect
  • This will create comp component under src/components/ folder and the index.jsx for this component will contain the same code written in the template.

  • For the page case, the index.jsx for that page will contain the code written in the template.

Redux

  • To create a redux implementation run:
rhc create -r
  • This will create a redux folder under the src/ folder containing the following:
src
└───redux
    │   index.js
    │
    ├───actions
    │   └───general
    │           index.js
    │
    └───reducers
        │   index.js
        │
        └───general
                index.js
  • Where index.js under the redux folder contains the redux store definition:
import { applyMiddleware, compose, createStore } from "redux";
import { mainReducer } from "./reducers";

/**
 * the main redux state, with all the reducers
 */
export const mainStore = createStore(
  mainReducer,
  compose(applyMiddleware(thunk))
);

/**
 * Creates a new redux state each time this function is called, this is used only for unit tests, to ensure that we have fresh state on each individual test
 */
export const createMainStore = () => {
  return createStore(mainReducer, compose(applyMiddleware(thunk)));
};
  • And actions folder contains the action for each reducer, as for a example, at first rhc will create a sample reducer and action which is called general.

  • The general action's index.js contains:

// write your general actions here

// this is an example for an action
export const init = () => async (dispatch, getState) => {
  dispatch({ type: "UPDATE_GENERAL", payload: { message: "init created!" } });
};
  • And the general reducer's index.js contains:
const initialState = { message: "" };

export const general = (state = initialState, action) => {
  switch (action.type) {
    case "UPDATE_GENERAL":
      return { ...state, ...action.payload };
    default:
      return state;
  }
};
  • And the index.js file under the reducers folder contains the following:
import { combineReducers } from "redux";
import { general } from "./general";

export const mainReducer = combineReducers({
  general,
});
  • In TypeScript, the files will be written as the following:

redux/index.ts

import { applyMiddleware, compose, createStore } from "redux";
import { mainReducer } from "./reducers";

/**
 * the main redux state, with all the reducers
 */
export const mainStore = createStore(
  mainReducer,
  compose(applyMiddleware(thunk))
);

export type StateInterface = ReturnType<typeof mainStore.getState>;

/**
 * list of action types
 */
export type ActionType = "UPDATE_GENERAL";

export interface Action<T> {
  type: ActionType;
  payload: Partial<T>;
}

export type ThunkResult<
  A = Record<string, unknown>,
  E = Record<string, unknown>
> = ThunkAction<void, StateInterface, E, Action<A>>;

export type Dispatch<A> = ThunkDispatch<
  StateInterface,
  Record<string, unknown>,
  Action<A>
>;

redux/actions/general/index.ts

import { GeneralState } from "../../reducers/general";
import { ThunkResult } from "../..";

// write your general actions here

// this is an example for an action
export const init =
  (): ThunkResult<GeneralState> => async (dispatch, getState) => {
    dispatch({ type: "UPDATE_GENERAL", payload: { message: "init created!" } });
  };

redux/reducers/general/index.ts

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

export interface GeneralState {
  message: string;
}

export const general = (
  state: GeneralState = {
    message: "",
  },
  action: Action<GeneralState>
) => {
  switch (action.type) {
    case "UPDATE_GENERAL":
      return { ...state, ...action.payload };
    default:
      return state;
  }
};

redux/reducers/index.ts

import { combineReducers } from "redux";
import { general } from "./general";

export const mainReducer = combineReducers({
  general,
});
  • Reducers

1 - To create a reducer, you must have a redux implementation then run:

rhc create --reducer <reducer-name>

Example

rhc create --reducer auth
  • This will create a auth reducer under the src/redux/reducers/ folder and the index.js for this reducer will contain the same code written in the template.

src/redux/reducers/auth/index.js

const initialState = {};

export const auth = (state = initialState, action) => {
  switch (action.type) {
    default:
      return state;
  }
};
  • It will also add the reducer to the index.js file under the reducers folder to use it in the combineReducers function.

src/redux/reducers/index.js

import { combineReducers } from "redux";
import { auth } from "./auth";
import { general } from "./general";

export const mainReducer = combineReducers({
  auth,
  general,
});
  • If you don't have a redux implementation create using rhc create -r, this command will prompt:
Redux implementation does not exist
  • You can also overwrite the reducer by running:
rhc create --reducer <reducer-name> -o

2 - To create multiple reducers, you must have a redux implementation then run:

rhc create --reducer <reducer-name-1> <reducer-name-2> ...
  • This will also update your index.js file under the reducers folder to use the reducers you created.

  • Actions

  • To create an action, you must have a redux implementation as wee as the reducer you want to add an action for it, then run:

rhc create --action <reducer-name> <action-name>

Example

  • In this example we are going to create an action for the auth reducer, so we will run:
rhc create --action auth login
  • This will create a login action under the src/redux/actions/auth/ folder and the login.js for this action will contain the same code written in the template.

src/redux/actions/auth/#.js

export const loginAction = () => async (dispatch, getState) => {
  dispatch({ type: "AUTH_LOGIN", payload: {} });
};
  • And it will update the index.js file under src/redux/actions/auth/ to export the action.

src/redux/actions/auth/index.js

export { loginAction } from "./#";

2 - To create multiple actions, you must have a redux implementation and existed reducer, then run:

rhc create --action <reducer-name> <action-name-1> <action-name-2> ...
  • If the reducer doesn't exist, you will get an error like this:
./src/redux/reducers/x does not exist
  • Keep in mind that this also works for TypeScript projects. Even better when creating an action for a reducer in TypeScript, you will get TypeScript support as well as updating the ActionType in the src/redux/index.ts file. For example if you create an action for the auth reducer, you will get the following:

src/redux/index.ts

import { applyMiddleware, compose, createStore } from "redux";
import thunk, { ThunkAction, ThunkDispatch } from "redux-thunk";

import { mainReducer } from "./reducers";

/**
 * the main redux state, with all the reducers
 */
export const mainStore = createStore(
  mainReducer,
  compose(applyMiddleware(thunk))
);

/**
 * Creates a new redux state each time this function is called, this is used only for unit tests, to ensure that we have fresh state on each individual test
 */
export const createMainStore = () => {
  return createStore(mainReducer, compose(applyMiddleware(thunk)));
};

export type StateInterface = ReturnType<typeof mainStore.getState>;

/**
 * list of action types
 */
export type ActionType = "AUTH_LOGIN" | "UPDATE_GENERAL";

export interface Action<T> {
  type: ActionType;
  payload: Partial<T>;
}
export type ThunkResult<
  A = Record<string, unknown>,
  E = Record<string, unknown>
> = ThunkAction<void, StateInterface, E, Action<A>>;

export type Dispatch<A> = ThunkDispatch<
  StateInterface,
  Record<string, unknown>,
  Action<A>
>;
  • It will also update the necessary files that imports and exports modules in order to use the action in the reducer.

  • Also another note, if you prefer not using redux-thunk you can set that in rhc.config.json file, this will let you create your store and actions without applying the redux-thunk middleware (For more details check configuration section).

Configuration

With the above steps, you can now create a configuration file which will be used by rhc to create your files with your custom config.

  • To create a default configuration file run:
rhc create --config
  • This will create a rhc.config.json file at the root of your project. The file will contain the following:
{
  "withCSS": true,
  "withFunctions": true,
  "withProps": true,
  "defaultExports": true,
  "componentsRoot": "./src/components",
  "pagesRoot": "./src/pages",
  "reduxRoot": "./src/redux",
  "applyReduxThunk": true
}
  1. withCSS: if true, create styles.css file for components and pages, if false, don't create styles.css file, default is true.
  2. withFunctions: if true, create functions folder for pages, if false, don't create functions folder, default is true.
  3. withProps: if true, create props interface for components and pages (in TS only), if false, don't create props interface, default is true.
  4. defaultExports: if true, create default export for components and pages, if false, create named export for components and pages, default is true.
  5. componentsRoot: the root folder for components, default is ./src/components.
  6. pagesRoot: the root folder for pages, default is ./src/pages.
  7. reduxRoot: the root folder for redux, default is ./src/redux.
  8. applyReduxThunk: if true, apply redux-thunk middleware to the store, if false, don't apply redux-thunk middleware, default is true.
  • If no configuration file is found or you don't specify some of the configuration, the default configuration will be used.