React custom hook: Is there a way to set a property dynamically?

874 views Asked by At

I have a row of headers in which I would like to attach a clickHandler to control the ASC and DESC of data for their respective column.

My brute force attempt was to loop all the headers and create an object which would have a property to represent each header with a value to let the hook know which is active or not i.e. in ASC or DESC:

{ 1: false, 2: false, 3: false....}

The code:

function addPropToObj(arr) {
  var obj = {}
  arr.forEach(o => {
    obj[o.id] = false;
  })
  return obj;
}

const activeObj = addPropToObj(userData)

function useActiveToggle(initialState = activeObj, bool = false) {
  const [state, setState] = React.useState(initialState);

  const toggle = React.useCallback((id) => {
    return setState((previousState) => ({ ...previousState, [id]: !previousState[id] }))
  }, [])

  return [state, toggle]
}

They're only 199 objects in the array, but what if there were 1000, or 10,000?

I know I've heard objects are cheap in JS but it doesn't feel right.

So I tried this:

function useActiveToggle(initialState = {}, bool = false) {
  const [state, setState] = React.useState(initialState);

  const toggle = React.useCallback((id) => {


    return setState((previousState) => {
      if (!previousState[id]) {
        previousState = { ...previousState, ...{ [id]: true } }
      }
      return ({ ...previousState, [id]: !previousState[id] })
    })
  }, [])

  return [state, toggle]

}

But that results in a mess! Strange behaviors!

A part of me thinks my brute force idea might not be too horrible, correct me if I'm wrong but how could react do something like this with all the reconciliation it has to deal with?

Anyone have an idea how to approach this?

1

There are 1 answers

8
Marson Mao On

Just guessing this is what you want?

function useActiveToggle(initialState = {}, bool = false) {
  const [state, setState] = React.useState(initialState);

  const toggle = React.useCallback((id) => {
    setState((previousState) => { // not "return setState", just do "setState"
      const prevValue = Boolean(previousState[id]); // get previous value, undefined also equals to false
      const nextState = {
        ...previousState,
        [id]: !prevValue, // invert the value
      };
      return nextState;
    });
  }, [])

  return [state, toggle]
}