0

I am new to react and office-ui-fabric and have been having issues understanding how to add a dropdown to useEffect. The user selects options from the dropdown and i need useEffects to monitor the value selected to another user so that i can send the value selected to another function.

const options: IDropdownOption[] = [
  { key: "A", text: "A", itemType: DropdownMenuItemType.Header },
  { key: "B", text: "B" },
  { key: "C", text: "C" }
];

const [selectedItem, setOption] = React.useState("");

React.useEffect(() => {
  window.addEventListener("message", ev => {
    switch (ev.data.command) {
      case "selectedItem": {
        console.log(`Got message`);
        setOption(ev.data.payload);
        break;
      }
    }
  });
}, []);

let test = () => {
  console.log("Test");
  vscode.postMessage({
    command: "setOption",
    text: "select option"
  });
  window.console.log(`Sent message.`);
};

return (
  <div>
    <Stack>
      <Stack.Item grow>
        <Label style={{ color: "white" }}>Select Option</Label>
        <Dropdown
          placeholder="Select option"
          options={options}
          styles={dropdownStyles}
          selectedKey={selectedItem}
          onChanged={selectedOption => {
            setOption(selectedOption.text);
            console.log(selectedOption.text);
            test;
          }}
        />
      </Stack.Item>
    </Stack>
    `enter code here`
  </div>
);

Currently i don't see the log "Test" inside test() or any of the logs "Got message" etc which means test is not getting triggered. Is this the right way ?or should i have an onClick like functionality for test ?

Chris Heald
  • 61,439
  • 10
  • 123
  • 137
novice_coder
  • 147
  • 2
  • 10

2 Answers2

0

Your test function isn't firing because you're not calling it; you have the bare token test, rather than the function invocation test().

Rather than wiring up your side effect handlers inside the event handler directly, though, use useEffect (which might better be called useSideEffect) and specify that you want it to fire when you alter your selectedItem:

// Whenever the value of selectedItem changes, fire this callback
// selectedItem will change as a consequence of setOption() being called
React.useEffect(() => {
    vscode.postMessage({
        command: "setOption",
        text: selectedItem
    });
}, [selectedItem])

// Define a callback with a hook, so we don't generate a new
// anonymous function every render
const onItemChanged = React.useCallback(e => setOption(e.text), [setOption]);

<Dropdown ... onChanged={onItemChanged} />

The second parameter to useEffect is a list of values to monitor. When this component re-renders, and the value of any of the listed items has changed, the defined function is invoked.

By defining your callback function with useCallback, rather than as an anonymous function to be redefined every time your component is re-rendered, you'll avoid extra garbage generation and can easily keep your logical list of "things to do when this changes" together.

Chris Heald
  • 61,439
  • 10
  • 123
  • 137
  • Thank you for your suggestion! I tried implementing it and ran into an error on the line const onItemChanged = React.useEffect(e => setOption(e.text), [setOption]); The error being argument of type (e:any)=>void is not assignable to parameter of type 'EffectCallback' . Does this mean i should be using the React.useCallback instead? – novice_coder Sep 05 '19 at 00:34
  • thank you! This fixed the issue i was had but when i used React.useCallback i can also see a log of the current as well as the previous option selected from the dropdown. Does useCallback just store the previous value or should i be concerned if the right value is being passed ? – novice_coder Sep 05 '19 at 18:01
  • React hooks are a little funny in that they create closures over previous values; any value you need to reference inside the hook needs to be in the list passed as the second argument. Otherwise, you'll get a stale value from an older version of the hook. I recommend adding eslint-plugin-react-hooks to your eslint setup, which will help you catch referenced values that need to be added to the watch values list. – Chris Heald Sep 05 '19 at 18:13
0

At the end of the useEffect declaration, there is that empty brackets you put there. That is where you need to put all the dependencies (=triggers) of the effect, like selectedItem in this case.

Currently, the empty array tells it that it will never be triggered again.

alparius
  • 60
  • 8