@hilma/tools
TypeScript icon, indicating that this package has built-in type declarations

0.3.0 • Public • Published

Tools

Tools is a package that has some useful client side tools.

Installation

npm install --save @hilma/tools

Main exports:

provide - function

provide is a function that returns a HOC (Higher Order Component) that is used to eliminate nested providers in React.

without provide:

impoer React from 'react';

const App = () => {
    return (
        <AuthProvider>
            <ThemeProvider>
                <StylesProvider>
                    <div className="App">
                        {/** .... */}
                    </div>
                </StylesProvider>
            </ThemeProvider>
        </AuthProvider>
    );
}

export default App;

with provide:

impoer React from 'react';
import { provide } from '@hilma/tools';

const App = () => {
    return (
        <div className="App">
            {/** .... */}
        </div>
    );
}

export default provide(AuthProvider, ThemeProvider, StylesProvider)(App);

What provide does is wrap your component recursively for each component you pass to is. What this actually does looks something like this:

const App = () => {
    return (
        <div className="App">
            {/** .... */}
        </div>
    );
}

const Provided1 = () => (
    <StylesProvider>
        <App />
    </StylesProvider>
);

const Provided2 = () => (
    <ThemeProvider>
        <Provided1 />
    </ThemeProvider>
);

const Provided3 = () => (
    <AuthProvider>
        <Provided2 />
    </AuthProvider>
);

export default Provided3;

If you want to pass props to your provider, then you can pass an array where the first item is the provider and the second is an object that is the props of the provider:

import React from 'react';
import { provide } from '@hilma/tools';

const App = () => {
    return (
        <div className="App">
            {/** .... */}
        </div>
    );
}

export default provide([AuthProvider, { basename: "/" }], ThemeProvider, [StylesProvider, { style: "dark" }])(App);

withContext - function

withContext is a function that returns a HOC (Higher Order Component) that is used to consume multiple context objects via props in a class based component in React (can also be used with functional components but not necessary with useContext).

example:

import React, { Component } from 'react';
import { withContext } from '@hilma/tools';

class MyComponent extends Component {
    componentDidMount() {
        this.props.api...........
    }
    
    render() {
        return (
            <div>{this.props.theme........}</div>
        );
    }
}

const mapContextToProps = {
    theme: ThemeContext,
    api: ApiContext
}

export default withContext(mapContextToProps)(MyComponent);

Let's look at what's going on here. First of all we're passing an object to withContext. this object represents how you want context objects to be passed via props: The key is the name of the prop you want and the value is the context object you want to pass down via the key.

In the example, we pass a key of 'theme' and value of 'ThemeContext'. This means that the 'ThemeContext' value will be passed down via the 'theme' prop. This is the same with 'api' and 'ApiContext'.

createMobXContext - function

createMobXContext is a function that eliminates the boilerplate needed to use mobx with React.

import { makeAutoObservable } from 'mobx';

class ThemeStore {
    color = "dark";

    constructor() {
        makeAutoObservable(this);
    }

    setColor = color => {
        this.color = color;
    }
}

const theme = new ThemeStore();

In this instance, we need a way to pass around theme between our components. The best way to do this is to use React's context api. The problem with that is there is a lot of boilerplate needed to make it all happen. That's where createMobXContext comes in. Let's see how to use it:

class ThemeStore {
    ....
}

const theme = new ThemeStore();

export const [ThemeContext, ThemeProvider, useTheme] = createMobXContext(theme);

Here we pass to createMobXContext our store instance and get back an array with three items: The first being a context object that will hold our store for us, the second is a provider that we wrap our application with to provide the store, and the third is a hook that returns the store.

Let's look at an example of useing those items:

import { ThemeContext, ThemeProvider, useTheme } from '......';

const App = () => (
    <ThemeProvider>
        <ClassComp />
        <FuncComp />
    </ThemeProvider>
);

export default App;

class ClassComp {
    static contextType = ThemeContext;
    
    render() {
        return (
            <div>{this.context.color}</div>
        );
    }
}

const FuncComp = () => {
    const theme = useTheme();
    
    return (
        <div>{theme.color}</div>
    );
}

useAsyncState - hook

useAsyncState is a hook based on the useState but with some extra useful asynchronous functionality:

import { useAsyncState } from '@hilma/tools';

const Comp = () => {
    const [color, setColor, getColor] = useAsyncState('black');
    
    const updateColorWithAwait = async (event) => {
        const newColor = await setColor(event.target.value);
        console.log(newColor);
    }

    const updateColorWithCallback = (event) => {
        setColor(event.target.value, newColor => {
            console.log(newColor);
        });
    }

    const getColorAsync = async () => {
        const color = await getColor();
        console.log(color);
    }
    
    return <div></div>;
}

useAsyncState is very similar to useState. it returns a tuple with three items: state, setState and getState. state is your state, setState is your setter, and getState is a getter.

With useAsyncState, now the setState function returns a promise with the resloved value being the new state. You can also pass a callback to the setState function that receives the new state.

The getState function returns a promise with the resolved value being the current state. The reason this is needed is because with the regular state variable, you won't always have the current state, for example, if you use a piece of state in an effect and its not one of the dependencies of useEffect.

useAsyncEffect - hook

useAsyncEffect is a hook based on the useEff ect hook but with some extra useful asynchronous functionality. By default, useEffect doesn't accept an async function because the function returns a promise. It also doesn't accept an async cleanup function. The useAsyncEffect allows you to do both:

import { useAsyncEffect } from '@hilma/tools';

const Comp = () => {

    useAsyncEffect(async () => {
        // stuff

        return async () => {
            // more stuff
        }
    }, []);

    return <div></div>;
}

You don't have to call useAsyncEffect with an async function or an async cleanup function, you can do both, either one, or neither of them.

Note: Because the behavior of the cleanup can be asynchronous, the cleanup can be called after the next effect (if you don't send an empty dependency array).

isCapacitor - function

returns a boolean value. If true, your'e working in a Capacitor environment:

import { isCapacitor } from '@hilma/tools';

console.log(isCapacitor());

useMemoOnce - hook

useMemoOnce is a hook that calls useMemo with an empty dependency array. Not many use cases but when used, it's very explicit that you only want a memoized value calculated once:

import { useMemoOnce } from '@hilma/tools';

const Comp = () => {

    const value = useMemoOnce(() => {
        return {
            theme: "dark"
        }
    });

    return <div>{value.theme}</div>;
}

useCallbackOnce - hook

useCallbackOnce is a hook that calls useCallback with an empty dependency array. Not many use cases but when used, it's very explicit that you only want a memoized function calculated once:

import { useCallbackOnce } from '@hilma/tools';

const Comp = () => {

    const func = useCallbackOnce(async () => {
        await login();
    });

    return <button onClick={func}>click</button>;
}

getDisplayName - function

A function that accepts a React component and returns its name. (don't use in production):

import { getDisplayName } from '@hilma/tools';

const Comp = () => {
    return <div></div>;
}

console.log(getDisplayName(Comp)); // 'Comp'

AsyncTools - object

AsyncTools is an object that inlcudes some useful asynchronous functions:

to

to is a function that accepts an promise, and returns a promise with the resloved value being an array with two items, the first one being the rejected error (if there was one) and the seconde item being the resolved value (it there was one):

import { AsyncTools } from '@hilma/tools';

const getstuff = async () => {
    const [error, response] = await AsyncTools.to(fetch('/api/user/1'));
    if (error) return console.error(error);
    const data = await response.json();
    return data;
}

parseJSON

parseJSON is a function that accepts a response from a fetch request (specifically from the fetch function of the browser) and returns a promise with the resolve value being an object with some info about the response:

  • status: the response status.
  • ok: if the request was made successfully
  • json: the json response. if there's no response this will hold an object with a key value pair like ok
import { AsyncTools } from '@hilma/tools';

const getstuff = async () => {
    const { status, ok, json } = await AsyncTools.parseJSON(await fetch('/api/user/1'));
    if (!ok) return console.error(json);
    return json;
}

fetch

fetch calls the browser's fetch function but also parses the json response:

import { AsyncTools } from '@hilma/tools';

const getstuff = async () => {
    const data = await AsyncTools.fetch('/api/users/1');
    return data;
}

superFetch

superFetch calls AsyncTools.fetch but returns an promise with the resolved value being an array with two items. the first item is the json response (if there was one) and the second item, the rejected value (if there was one)

import { AsyncTools } from '@hilma/tools';

const getstuff = async () => {
    const [data, error] = await AsyncTools.superFetch('/api/users/1');
    if (error) return console.error(error);
    return data;
}

ValidateFields - object

An object that includes functions that validate inputs based on different types of information, like usernames, phonenumbers, names, email, and so on. Each function returns a string. If the value is valid, the string will be empty, if not, the string will be an error message in hebrew that describes what's not valid about the input. Let's look at one of these functions:

import { ValidateFields } from '@hilma/tools';

const isValid = ValidateFields.validateFullNameInput('הילמה הילמה');

console.log(isValid); // ''

const isValid = ValidateFields.validateFullNameInput('שדגכשדגכשגדכשדגכשדגכשדגכשדגכשדגכשדגכשדגכשדגכ');

console.log(isValid); // 'השם חייב להכיל פחות מ30 תווים'

Keywords

none

Install

npm i @hilma/tools

DownloadsWeekly Downloads

102

Version

0.3.0

License

MIT

Unpacked Size

109 kB

Total Files

115

Last publish

Collaborators

  • hilma
  • elsasebagh