sc0ttj / component

A tiny library for isomorphic JavaScript components
MIT License
2 stars 1 forks source link

Feature: add "React-like" modules #30

Closed sc0ttj closed 3 years ago

sc0ttj commented 3 years ago

Now the standalone render module has been added, a much more "React-like" pattern/syntax is now available.. html and htmel can already be used with the standalone render module, but it would be nice to expand this further.

Third-party tools

Find some good (lightweight, fast, standalone) redux, useState, useEffect alternatives.

Find ones that play nice with standalone render module (see https://github.com/sc0ttj/component/issues/25).

useState-like patterns:

redux-like patterns:


Others I would like:

useScroll

A debounced, performant scroll thingy, for doing infinite scroll, or scrollytelling stuff:

function Foo(props) {
  const { count, msg } = fromState([ 0, "initial" ]);

  useScroll(scrollProps => {
    // scrollProps contains info about scroll event, scroll progress, etc..
    // ..can also modify `props` here
  })

  return `<div>...</div>`
}

..also make this work:

import { Component, useScroll } from '@scottjarvis/component'

const Foo = new Component({ width: 0 });

Foo.useScroll(scrollProps => {
    // scrollProps contains info about scroll event, scroll progress, etc..
    // ..can also modify state and re-render here
   Foo.setState({ width: scrollProps.progress * 100 })
})
sc0ttj commented 3 years ago

https://gist.github.com/sc0ttj/e5949f68befe097f7e2bda105e5429c4#file-vanilla-js-components-js-L136

Forgot I ever did this... Can be added to docs, it's a nice little "Redux-like" pattern..

Can be extended to be a independent state manager.. Something like this:

// A simple function for managing the state updates of the given component

function stateManager(component, action, props) {

  const { state, setState } = component

  switch (action) {
    case 'state':
      setState(props)
      break
    case 'increment':
      setState({ count: state.count + 1 })
      break
    case 'decrement':
      setState({ count: state.count - 1 })
      break
    case 'items':
      setState({ items: props })
      break
    case 'addItems':
      setState({ items: [...state.items, ...props] })
      break
  }
}

// ...could be wrapped by individual components.. 

// make App use a stateManager "store"   
App.update = function(action, props) {
  stateManager(App, action, props)
}

// ..then you can do this:
App.update('increment')

Notes about the above:

If added to the users created component instances (the c function by Component):

// A function to set a reducer
c.useReducer = function(fn) {
  c.update = (action, props) => {
    const { state, setState } = c
    fn(action, props)
  }
}

So you could set your "reducer" like so:

// set a "reducer" function
App.useReducer((action, props) => {
  switch (action) {
    case 'increment':
      setState({ count: state.count + 1 })
      break
    case 'decrement':
      setState({ count: state.count - 1 })
      break
    case 'items':
      setState({ items: props })
      break
    case 'addItems':
      setState({ items: [...state.items, ...props] })
      break
  };
})

..and used like so:

App.update('increment')
App.update('addItems', [ "new 1", "new 2" ])

...I think that would work...


About "Redux" and "stores":

A "store" help you update individual properties in a component state... I think! .. they're bloody verbose and confusing..

Stores usually provide a createStore method, which normally takes an initialState and a reducerFunc. They return subscribe (listener) and dispatch (setter) methods.


/* 
 Mini Redux implementation  (from https://gist.github.com/jakoblind/6b90d0b677d26effcebbed69b24cb05f)
*/
function createStore(reducer, initialState) {
    var currentReducer = reducer;
    var currentState = initialState;
    var listener = () => {};

    return {
        dispatch(action) {
            currentState = currentReducer(currentState, action);
            listener()
            return action;
        },
        subscribe(newListener) {
            listener = newListener;
        },
        getState() {
            return currentState;
        }
    };
}

Usage:

function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}

let store = createStore(counter)

store.subscribe(() =>
  console.log(store.getState())
)

store.dispatch({ type: 'INCREMENT' })
store.dispatch({ type: 'DECREMENT' })
sc0ttj commented 3 years ago

Added TNG-Hooks.. Closing.