Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
react-app-modules
Advanced tools
An easy-to-use, type-safe IoC library for React apps.
@types
package ;)# npm
npm install react-app-modules
# yarn
yarn add react-app-modules
This tutorial will demonstrate how to use react-app-modules
to define, provide, and use a simple ICalculator
module.
It is recommended that the reader follows this tutorial by typing along (rather than copying / pasting) to get a sense of the type-safety that this library provides. Feel emboldened to try to use the api incorrectly; see for yourself what happens!
# create a new React app
npx create-react-app tutorial --template typescript
# enter the newly created directory
cd tutorial
# add this lovely package as a dependency
yarn add react-app-modules
Here is the directory structure used for the code in this tutorial, but feel free to use whatever structure works for you!
Our ICalculator
module will implement a single method, sum
,
which returns the arithmetic sum of a list of numbers.
// src/modules/definitions/calculator.ts
export interface ICalculator {
sum(numbers: number[]): number;
}
First, we are defining a Calculator
symbol, which represents any
implementation of the ICalculator
interface. Note that we have not
coupled ourselves to an implementation. While not covered in this tutorial,
the createProvider
api be used to return a DigitalCalculator
versus
an Abacus
, for example.
Next, we extend the internal AppModules
type within react-app-modules
. This
bit of magic is what gives us complete type-safety for all the api methods.
// src/modules/symbols.ts
import { ICalculator } from './definitions/calculator';
export const Calculator = Symbol('Calculator');
declare module 'react-app-modules' {
interface Types {
AppModules: {
[Calculator]: ICalculator;
};
}
}
If the following error displays in VSCode, don't panic! The error will
go away as soon as you import from react-app-modules
in any other file.
The provider is responsible for providing an implementation of ICalculator
.
To demonstrate module loading, we will emit an implementation after 1 second.
The createProvider
api is a convenient way to define a module implementation.
Note that this architecture allows a provider to dynamically provide an
implementation for the ICalculator
interface, as well as swap out for
various ICalculator
implementations during runtime, though that is out of
scope for this tutorial. Also, the createProvider
api can be used to indicate
module dependencies, but that is not covered in this tutorial for the sake of brevity.
// src/modules/providers/provide-calculator.ts
import { createProvider } from 'react-app-modules';
import { timer } from 'rxjs';
import { map } from 'rxjs/operators';
import { Calculator } from '../symbols';
export const provideCalculator = createProvider(Calculator, [], () =>
timer(1000).pipe(
map(() => ({
sum: (numbers) => numbers.reduce((total, n) => total + n),
})),
),
);
Now we will define an Example
component that uses our new Calculator
module.
Note that we are using the useModule
hook provided by react-app-modules
.
// src/components/example.tsx
import React from 'react';
import { useModule } from 'react-app-modules';
import { Calculator } from '../modules/symbols';
const Example = () => {
const calculator = useModule(Calculator);
if (calculator === null) {
return <span>Loading Calculator Module...</span>;
}
return <span>2 + 2 = {calculator.sum([2, 2])}</span>;
};
export default Example;
If you haven't been following along by typing, check this out:
Oh yeah.
We are almost there! First, we use the createContainer
api to compose
the set of module symbols with their respective providers. Then, we
supply the container to the AppContext.Provider
component, which the
useModule
hook depends upon. Finally, we render our Example
component
within the AppContext.Provider
.
// src/App.tsx
import React from 'react';
import { AppContext, createContainer } from 'react-app-modules';
import Example from './components/example';
import { provideCalculator } from './modules/providers/provide-calculator';
import { Calculator } from './modules/symbols';
const container = createContainer({
[Calculator]: provideCalculator,
});
const App = () => (
<AppContext.Provider value={container}>
<Example />
</AppContext.Provider>
);
export default App;
Time to fire that baby up.
yarn start
Observe that the module loads:
And then displays a result:
The examples that follow in this section assume that the following
modules are defined (extending the react-app-modules
internal types):
// src/modules/symbols.ts
export const Api = Symbol('Api');
export const Logger = Symbol('Logger');
declare module 'react-app-modules' {
interface Types {
AppModules: {
[Api]: {
doSomething(): Promise<void>;
};
[Logger]: {
log(message: string): void;
};
};
}
}
Provides module implementations to your components at runtime without having to pass props around. For more information, see: Context.
Props
value
: a container created via createContainer
Example
// src/App.tsx
import React from 'react';
import { AppContext } from 'react-app-modules';
import Example from './components/example';
import { container } from './modules/container';
const App = () => (
<AppContext.Provider value={container}>
<Example />
</AppContext.Provider>
);
export default App;
Maps a set of module symbols to their respective providers.
The result is passed to the AppContext.Provider
component
as a value
prop.
Params
providers
: an object whose keys are the set of all defined module symbols
and whose values are a set of providers for those modulesExample
// src/modules/container.ts
import { createContainer } from 'react-app-modules';
import { Api, Logger } from './symbols';
import { provideApi, provideLogger } from './providers';
export const container = createContainer({
[Api]: provideApi,
[Logger]: provideLogger,
});
Defines an implementation associated with a module symbol. Modules may have dependencies on other modules, but circular dependencies are prohibited.
Params
symbol
: the module symbol that we are defining an implementation fordependencySymbols
: an array of module symbols that this module depends onimplementation
: a callback function returning an observable whose value
implements this module's interfaceimplementation
is called when all dependencySymbols
have been resolved.
It can take the following parameters:
dependencies
: an object whose keys are the set of all dependencySymbols
and whose values implement the dependency interfacesExample
// src/modules/providers.ts
import { createProvider } from 'react-app-modules';
import { Api, Logger } from './symbols';
// Provider without dependencies
export const provideLogger = createProvider(Logger, [], () => of({
log: (message) => console.log(message),
}));
// Provider with dependencies
export const provideApi = createProvider(Api, [Logger], ({ [Logger]: logger }) => of({
doSomething: () => {
logger.log('doing something...');
return Promise.resolve();
},
}));
React hook that returns an object implementing the interface defined
for the provided module symbol. Returns null
if the module has not
been resolved yet.
Params
symbol
: the module symbol we want to use in this componentExample
// src/components/example.tsx
import React from 'react';
import { useModule } from 'react-app-modules';
import { Logger } from '../modules/symbols';
const Example = () => {
const logger = useModule(Logger);
if (logger === null) {
return <span>Loading Logger Module...</span>;
}
logger.log(' :) ');
return <span>Check the console!</span>;
};
export default Example;
Dependencies
yarn
Build
yarn build
Test
yarn test
Publish
yarn publish
Update README Table of Contents
npx doctoc README.md
FAQs
An easy-to-use, type-safe IoC library for React apps.
The npm package react-app-modules receives a total of 1 weekly downloads. As such, react-app-modules popularity was classified as not popular.
We found that react-app-modules demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.