简体   繁体   中英

Passing React-Redux useSelector Hook as Props

Precursor: I'm fairly new to Redux, but I know enough about coding that I know the following solution is not ideal. Although it works, I'm really iffy about using eval() and passing a hook as a string. I'm looking to see if there is a better way to do this or if React-Redux has a built in functionality for what I'm trying to achieve.

Scenario: All of my ChildComponents in the code below are generic components (dropdowns, etc.) that should not include code baked in them linking them to specific items; I'm trying to keep them as generic as possible. However, when checkBox1 triggers a dispatch to change Item1 in the store, I only want the intended Dropdown (dropdown2) to rerender and not the whole ParentComponent (and by extension all of the children). I also want dropdown2 to update it's options each time Item1 is changed in the store. The only way I can think to do this without foring a rerender of the entire ParentComponent is to deploy the useSelector hook in the child. I don't want to explicitly declare the hook in the child though because that violates abstraction and forces me to put workaround code in the generic Dropdown component.

Side Note: I've considered some how declaring useSelector in the Parent and preventing it from forcing a rerender, but the props would still have to change on dropdown2 which would still force a rerender of the Parent to reflect dropdown2's new props.

const ParentComponent = () => {

  let passSelector = "selector(state => state.Item1 ? state.Item2.concat(state.Item3) : state.Item2)";

  let dropdown1 = <Dropdown input={[thing1, thing2]} />;
  let dropdown2 = <Dropdown input={passSelector} />
  let checkbox1 = <Checkbox onClick={() => dispatch(toggleItem1)} />;

  let menu1 = [dropdown1];
  let menu2 = [dropdown2, checkbox1];

  return (
    <div>
      <Checkbox1 onClick={doThing} />
      <Switch onSwitch={switchyThing} />
      {mode &&
         menu1
      }
      {!mode &&
         menu2
      }
    <div/>
  );
}

const Dropdown = ({input}) => {
  const selector = useSelector; // Grabbed from the import statements to force importation.
  const options = (typeof input === 'string') ? eval(input) : input;

  ... some other code ...

  return (
    {options && options.map(option => {
      ...do thing with option...
    }
  );
}   

You can probably pass just the function that you want to use as a selector from the parent to the children, instead the string. Something like this?

const ParentComponent = () => {

  const selector = state => state.Item1 ? [...state.Item2, ...state.Item3] : state.Item2;

  return (
    <div>
      <Dropdown selector={selector} />
    <div/>
  );
}

const Dropdown = ({selector}) => {
  const options = useSelector(selector);

  //... some other code ...

  return (
    {options && options.map(option => {
      //...do thing with option...
    }
  );
}   

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM