Create Redux
To create a redux implementation run:
rnhc create -r
- This will create a
redux
folder under thesrc/
folder containing the following:
- JavaScript
- TypeScript
src/
└── redux
├── actions
│ └── general
│ └── index.js
├── index.js
└── reducers
├── general
│ └── index.js
└── index.js
src/
└── redux
├── actions
│ └── general
│ └── index.ts
├── index.ts
└── reducers
├── general
│ └── index.ts
└── index.ts
- Where
index.*
under theredux
folder contains the redux store definition:
- JavaScript
- TypeScript
import { applyMiddleware, compose, createStore } from "redux";
import { mainReducer } from "./reducers";
import thunk from "redux-thunk";
/**
* 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)));
};
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 = "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>
>;
And
actions
folder contains the action for each reducer, as for a example, at firstrnhc
will create a sample reducer and action which is calledgeneral
.The
general
action'sindex.*
contains:
- JavaScript
- TypeScript
// write your general actions here
// this is an example for an action
export const initAction = () => async (dispatch, getState) => {
dispatch({ type: "UPDATE_GENERAL", payload: { message: "init created!" } })
};
import { GeneralState } from "../../reducers/general";
import { ThunkResult } from "../..";
// write your general actions here
// this is an example for an action
export const initAction =
(): ThunkResult<GeneralState> => async (dispatch, getState) => {
dispatch({ type: "UPDATE_GENERAL", payload: { message: "init created!" } });
};
- And the
general
reducer'sindex.*
contains:
- JavaScript
- TypeScript
const initialState = { message: "" };
export const general = (
state = initialState,
action,
) => {
switch (action.type) {
case "UPDATE_GENERAL":
return { ...state, ...action.payload };
default:
return state;
}
};
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;
}
};
- And the
index.*
file under thereducers
folder contains the following:
- JavaScript
- TypeScript
import { combineReducers } from "redux";
import { general } from "./general";
export const mainReducer = combineReducers({
general,
});
import { combineReducers } from "redux";
import { general } from "./general";
export const mainReducer = combineReducers({
general,
});
Reducers
Create a reducer
- To create a reducer, you must have a redux implementation then run:
rnhc create --reducer <reducer-name>
Example
rnhc create --reducer auth
- This will create a
auth
reducer under thesrc/redux/reducers/
folder and theindex.*
for this reducer will contain the same code written in the template.
src/redux/reducers/auth/index.*
- JavaScript
- TypeScript
const initialState = { };
export const auth = (
state = initialState,
action,
) => {
switch (action.type) {
default:
return state;
}
};
import { Action } from "../..";
export interface AuthState { }
export const auth = (
state: AuthState = { },
action: Action<AuthState>,
) => {
switch (action.type) {
default:
return state;
}
};
- It will also add the reducer to the
index.*
file under thereducers
folder to use it in thecombineReducers
function.
src/redux/reducers/index.*
- JavaScript
- TypeScript
import { combineReducers } from "redux";
import { auth } from "./auth";
import { general } from "./general";
export const mainReducer = combineReducers({
auth,
general,
});
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
rnhc create -r
, this command will prompt:
Redux implementation does not exist
- You can also overwrite the reducer by running:
rnhc create --reducer <reducer-name> -o
Create multiple reducers
- To create multiple reducers, you must have a redux implementation then run:
rnhc create --reducer <reducer-name-1> <reducer-name-2> ...
- This will also update your
index.*
file under thereducers
folder to use the reducers you created.
Actions
Create an action
- 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:
rnhc 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:
rnhc create --action auth login
- This will create a
login
action under thesrc/redux/actions/auth/
folder and thelogin.*
for this action will contain the same code written in the template.
src/redux/actions/auth/login.*
- JavaScript
- TypeScript
export const loginAction = () => async (dispatch, getState) => {
dispatch({ type: "AUTH_LOGIN", payload: { } })
}
import { AuthState } from "../../reducers/auth";
import { ThunkResult } from "../..";
export const loginAction = (): ThunkResult<AuthState> => async (dispatch, getState) => {
dispatch({ type: "AUTH_LOGIN", payload: { } })
}
- And it will update the
index.*
file undersrc/redux/actions/auth/
to export the action.
src/redux/actions/auth/index.*
- JavaScript
- TypeScript
export { loginAction } from "./login";
export { loginAction } from "./login";
Create multiple actions
- To create multiple actions, you must have a redux implementation and existed reducer, then run:
rnhc 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 thesrc/redux/index.ts
file. For example if you create an action for theauth
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 inrnhc.config.json
file, this will let you create your store and actions without applying theredux-thunk
middleware (For more details check configuration section).