1.0.2 • Published 10 months ago

wcs-react-tools v1.0.2

Weekly downloads
-
License
MIT
Repository
-
Last release
10 months ago

WCS React Tools

version react

a react-hook collection

Index

StateController

A tiny but powerful state management for React. It is less than a hundred lines long and has no external dependencies.

function StateController (options)

Returns a controller object with these properties:

  • state
    a more or less complex object holding the application state

  • actions
    a optional list of actions

  • setState(newState)
    a function for manipulating the state

  • useState()
    a react hook similar to the function of the same name from React

  • addListener(func)
    a function for subscribing to state changes

  • removeListener(func)
    a function for unsubscribing

Counter Demo

import React from "react";
import {StateController} from 'wcs-react-tools'

const controller = StateController({
    initial: {
        counter: 0, 
        counterId: 1, 
        children: []
    },
    actions: {
        inc() {
            this.setState(prev => ({ counter: prev.counter + 1 }));
        },
        remove(id) {
            this.setState(prev => ({children: prev.children.filter(e => e !== id )}));
        }
    },
})


export default function App() {

    const [state, setState] = controller.useState();
    const {children,counterId} = state;

    const addCounter = () => {
        setState({
            children: [...children, counterId],
            counterId: counterId + 1,
        });
    };
    
    return (
        <div className="App">
            <h1>Counter Demo</h1>
            <button onClick={addCounter}>Add Counter</button>
            <div className="container">
                {children.map( id => <Counter key={id} id={id} />)}
            </div>
        </div>
    );
}


function Counter(props) {
    const {counter} = controller.useState()[0];
    const {id} = props;
    const remove = () => controller.actions.remove(id);
    return (
        <div className="Counter">
            <span>Counter ({id}):{' '}{counter}</span>
            {' '}
            <button onClick={controller.actions.inc} >
                +1 to global
            </button>
            {' '}
            <button onClick={remove} >
                remove
            </button>
        </div>
    );
};

Hints

The StateController function accept a options object. Property options.initial is initial state. The state must be a object. Property options.action is an object with functions. The functions will bound to the resulting object, so you can use this.

The useState hook returns state,setState where both are the same as the controller properties.

The setState argument is either an object branch or a function that returns an object branch.

c = StateController({initial: {count:1, other: 'keep'}})
assert.deepEqual(c.state, {count:1, other: 'keep'})

// simple increment
c.setState( prev => ({count: prev.count + 1}))
assert.deepEqual(c.state, {count:2, other: 'keep'})
// todos example

c.state = {
    todos: [
      { id: 1, text: 'Learn React', completed: false },
      { id: 2, text: 'Build an app with React', completed: false }
    ]
};
var nextState = draft => {
    draft.todos.push({ id: 3, text: 'Test React', completed: true });
    draft.todos[0].completed = true;
    return draft;
};
var expected = {
    todos: [
      { id: 1, text: 'Learn React', completed: true },
      { id: 2, text: 'Build an app with React', completed: false },
      { id: 3, text: 'Test React', completed: true }
    ]
};
c.setState( nextState );
assert.deepEqual(c.state, expected );

withStateController

A higher-order component (HOC) to connect a class component to StateController.

function withStateController (Component, controller)

returns wrapped component with state, setState and actions in props.


RemoteController

A tiny controller to controll a component's state from outside.

function RemoteController (initialProps = {})

returns the controller object.

useRemote

A React hook.

function useRemote (controller)

const [remoteProps, setRemoteProps] = useRemote (controller);

withRemote

A higher-order component (HOC) to connect a class component to RemoteController.

function withRemote (Component, controller)

returns wrapped component with state props injected from controller.


DragSort

A React helper hook to sort a list per drag and drop.

function DragSort (list, setList)

  • list is the array to be sorted
  • setList is the function to store reordered list

Function DragSort returns an object with all required functions and the React hook. The function dragProps of the object can inject all html attributes like draggable, onDragStart and so on.

Usage example:

import React from 'react';
import {ListGroup, ListGroupItem} from 'reactstrap';
import {DragSort} from 'wcs-react-tools';

export default function MyList (props) {
    const [list,setList] = React.useState(['item 1','item 2','item 3']);
    const drag = DragSort(list, setList);  // create drag object
    const items = list.map( (item,index) => { // create item JSX
        var itemProps = {
            key: index,
            ...drag.dragProps(index)   // inject dragProps
        }
        return <ListGroupItem {...itemProps} >{item}</ListGroupItem> // return item JSX
    });
    return <ListGroup {...{style: {maxWidth: '20rem'}, ...props}} >
        {items}
    </ListGroup>;
}

useListSelect

A React hook to simplify the selection in lists.

  • select one or more list items with mouse click
  • select a range of items with mouse
  • skip and select items bei name per keyboard
  • auto select first item after mount

usage

function List({items}) {

    const aSel = useListSelect({
        length:         items.length,
        getSearchWord:  index => items[index].name,
    }, items);

    return <ul>
        {items.map( (item,index) => {
            item.key = index + 1;
            return (
                <li key={item.key} {...
                    {
                        onDoubleClick: ev => onOpen(item, ev),
                        ...aSel.itemProps(index),
                    }} 
                />
                    {item.name}
                </li>
            )
        })}
    </ul>
}

The hook works with index, a value from 0 to list lenght - 1. The returned object supplies some properties and functions

  • selected
    is a array of selected indexes

  • select
    is a function to change the selection
    function select(newSelection)
    newSelection is a array of indexes, a single index or undefined to clear selected

  • isSelected
    is a function to test if a index is selected
    function isSelected(index)

  • itemProps(index)
    is a function that returns an object whose properties are injected into jsx

options

  • length
    length is the length of list. Alternatively, maxIndex can also be set

  • maxIndex
    same as length-1

  • multiselect
    default is 'true'

  • autoselect
    default is 'false'.
    Set 'true' to select the first item on mount.
    The require the 'items' as second argument.

  • keydisable
    default is 'false', set 'true' to disable key down handle

  • handleKeyDown
    default is 'undefined' set function for custom key down handling

  • getSearchWord
    default is 'null'.
    Set it to a function that retuns a search word to enable a jump on keyboard press.
    example: (index) => myItems[index].label

  • id
    a id prefix used to scroll to search word

handleKeyDown example

handleKeyDown:  (event,index) => {
    if (event.key === 'Enter') {
        console.log('Enter', index)
        return true;
    }
},

1.0.2

10 months ago

1.0.0

11 months ago