renatorib / react-powerplug

:electric_plug: [Unmaintained] Renderless Containers

Home Page:https://renatorib.github.io/react-powerplug

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

<Debounce /> and <Throttle /> component

pedronauck opened this issue · comments

Everytime that we need to make a debounce or a throttle on some method the process is very annoying. I think that maybe this two components can be useful:

Debounce

<Debounce method={() => console.log('helo')} timer={200}>
  {({ fn }) => /* ... */}
</Debounce>

Throttle

<Throttle method={() => console.log('helo')} timer={200}>
  {({ fn }) => /* ... */}
</Throttle>

@pedronauck can you show me a use case? In all use cases I can think I can solve by just using a debounce/throttle fn. A component might be an overkill in these cases.

Really, just using a debounce/throttle method like a lodash helper solve the problem. The point is to be able to do that without any other dependency. I can have some state on my component just by using a class component, but using your <State> is more quick and easy. In my head, you can implement your own debounce throttle and give us this power without dependencies too!

I got yout point, but I think its more simpler to manage your debounce/throttle by yourself:

import { Value, Debounce } from 'react-powerplug'

<Value>
  {text => (
    <Debounce fn={text.set} wait={200}>
      {({ fn }) => (
        <input value={text.value} onChange={e => fn(e.target.value)} />
      )}
    </Debounce>
  )}
</Value>

vs.

import { Value } from 'react-powerplug'
import debounce from 'lodash.debounce'

<Value>
  {text => {
    const setText = debounce(text.set, 200)
    return <input value={text.value} onChange={e => setText(e.target.value)} />
  }}
</Value>

Really, good point 🙏

@renatorib Isn't this leaky? Just never tried to fit debounce to render in my mind.

🤔 Yeah, maybe.

I tried here and debounce worked (don't know about perf). But throttle doesn't.

Yep. There should be persistent state for timers.

I tried something at the constructor: https://codesandbox.io/s/kk0190xnk5

As to Debounce or Throttle, I think LifeCycle is much more common:

like in https://github.com/xialvjun/xialvjun.github.io/blob/master/_posts/2018-05-22-react-render-props.md

<LifeCycle
  props={{ list }}
  getDerivedStateFromProps={(props, state) => {
    const plist = props.list,
          slist = state.list;
    if (plist.length > slist.length) {
      return {
        list: plist.map(pit => 
          slist.findIndex(sit => sit.id===pit.id) > -1 ?
            pit :
            { ...pit, just_insert: true }
        )
      }
    }
    if (plist.length < slist.length) {
      return {
        list: slist.map(sit =>
          slist.find(pit => sit.id===pit.id) ||
          { ...sit, just_remove: true }
        )
      }
    }
    return props;
  }}
  componentDidUpdate={(prevProps, prevState, snapshot, instance) => {
    setTimeout(() => {
      instance.setState(state => ({ list: state.list.filter(it => !it.just_insert && !it.just_remove) }));
    }, 300);
  }}
>
  {state => state.list.map(it => (
    <div key={it.id} className={`${it.just_insert ? 'inserting' : ''} ${it.just_remove ? 'removing' : ''}`}>
      content
    </div>
  ))}
</LifeCycle>

So, a Debounce is just:

<LifeCycle
  props={{ list }}
  shouldComponentUpdate={(nextProps, nextState, instance) => nextState !== instance.state}
  componentWillReceiveProps={(nextProps, instance) => {
    clearTimeout(instance.debounce_timeout);
    instance.debounce_timeout = setTimeout(() => instance.setState(nextProps), 300);
  }}
>
  {state => xxx}
</LifeCycle>

I actually wrote a little Debounce component: https://github.com/fea17e86/react-beco. I just realised that this issue was open.

:-O Write a Debounce and Throttle component is easy. But the hard point is to decide should we include it in react-powerplug.