DEV Community

loading...

Have you meet hook trap? see how concent resolve it

fantasticsoul profile image 幻魂 ・2 min read

Star Concent if you are interested in it, I will appreciate it greatly.

attention hook dependency

When we write the below code, eslint may tip us pass dependency if you want the component works well

function NormalDemo() {
  const [count, setCount] = useState(0);
  const dom = useRef(null);
  useEffect(() => {
    const cur = dom.current;
    const add = () => setCount(count + 1);
    cur.addEventListener("click", add);
  }, []);
  return <div ref={dom}>normal {count}</div>;
}

so we should add the count to dep-list

  useEffect(() => {
    // ...
  }, [count]);

we should attention that in every render period, we add a event listener to the dom ref, but we forget to remove the ref's previous render period listener, so the right code should be like below

  useEffect(() => {
    // ...
    cur.addEventListener("click", add);
    return ()=> cur.removeEventListener("click", add)
  }, [count]);

if we use concent, no traps any more

With concent setup feature, and it supports class component and function component both, we can easily write the right code.

  • define setup first
const setup = ctx=>{
  const addCount = () => {
    const count = ctx.state.count;
    ctx.setState({count: count + 1});
  }

  // just like useEffect, but here no dependency
  ctx.effect(()=>{
    const cur = ctx.refs.dom.current;
    cur.addEventListener('click', addCount);
    return ()=>cur.removeEventListener('click', addCount);
  }, []);

  return { addCount }
}
  • declare a class component
// or @register({setup, state:{count:0}})
@register({setup})
class ConcentClassDemo extends React.Component{
  state = {count:0}
  render(){
    const {useRef, state, settings} = this.ctx;
    // this.ctx.state === this.state
    return (
      <div>
        <div ref={useRef('dom')}>class {state.count}</div>
        <button onClick={settings.addCount}>add</button>
      </div>
    )
  }
}
  • declare a function component
function ConcentFnDemo() {
  const {useRef, state, settings} = useConcent({setup, state:{count:0}});
  return (
    <div>
      <div ref={useRef('dom')}>fn {state.count}</div>
      <button onClick={settings.addCount}>add</button>
    </div>
  )
}

Just look the code above, you will find concent expose the 100% same api to class component and function component both, so it allow you switch component style whatever you want.

one more thing

If we want to do something when count change, how could we do? just put the key name is enough.

const setup = ctx=>{
  ctx.effect(()=>{
    //detect count changed in didMount or didUpdate
  },['count']);
}

here is online demo

Discussion (0)

Forem Open with the Forem app