sybercoda
sybercoda

Reputation: 565

Wrapping functional component to use forwardRef results in Unexpected Token error

ReactJS newbie question. I'm trying to wrap my EmergencyService.js functional component with forwardRef so that I can reference the ref in SearchBar.js by following this tutorial https://codezup.com/forwardref-in-functional-components-react-hooks/ but when I try doing so I receive an Unexpected Token error. The only edit I made to EmergencyService.js is replace "export default function EmergencyService() {" with "const EmergencyService = (props, ref) => (" on line 158 and added "export default React.forwardRef(EmergencyService);" to the bottom. I'm not sure why this error is occurring. I also tried just wrapping only the return but received the same error. Any help would be greatly appreciated. Please feel free to view my code at https://codesandbox.io/s/twilight-waterfall-3okx4?file=/src/EmergencyService.js

Upvotes: 1

Views: 1868

Answers (2)

Shubham J.
Shubham J.

Reputation: 646

I have gone through your codesandbox. Updated a little bit code, let me know if it helps.

import React from "react";
import TextField from "@material-ui/core/TextField";
import Autocomplete from "@material-ui/lab/Autocomplete";
import styled from "styled-components";
import { makeStyles } from "@material-ui/core/styles";
import IconButton from "@material-ui/core/IconButton";
import ClearIcon from "@material-ui/icons/Clear";
import clsx from "clsx";

const autocompleteDefaultWidth = 180;

const useStyles = makeStyles((theme) => ({
  icon: {
    color: theme.palette.text.secondary,
    marginRight: theme.spacing(2)
  },
  searchField: {
    marginTop: "-12px",
    "& .MuiFilledInput-root": {
      background: "none"
    },
    width: "100%",
    transition: "width 0.5s"
  },
  inputLabel: {
    color: "#3c3b37",
    backgroundColor: "none",
    padding: "0 5px 0 5px",
    "&.focused": {
      color: "black",
      backgroundColor: "#fbfbf8"
    }
  },
  autocompleteBase: {
    display: "inline-block",
    height: "42px",
    transition: "width 0.5s",
    paddingLeft: "30px",
    //paddingRight: "30px",
    borderRadius: "9999px",
    minWidth: "210px",
    float: "left"
  },
  autocompleteOnFocus: {
    backgroundColor: "#ffffff",
    borderBottom: "1px solid #989586",
    webkitBoxShadow: "0 2px 4px rgba(0,0,0,.08),0 4px 12px rgba(0,0,0,.08)",
    boxShadow: "0 2px 4px rgba(0,0,0,.08),0 4px 12px rgba(0,0,0,.08)",
    transition: "width 0.5s, min-width 0.5s",
    minWidth: "285px",
    "&:hover $clearIndicatorDirty, & .Mui-focused $clearIndicatorDirty": {
      visibility: "visible !important",
      right: "8px",
      position: "absolute",
      top: "4px"
    },
    "& .MuiInputBase-input": {
      width: "100%"
    }
  },
  autocompleteCustom: {
    position: "relative",
    "&:hover": {
      backgroundColor: "#f0f0eb",
      cursor: "pointer",

      "&::after": {
        display: "none"
      }
    },
    "&::after": {
      content: '""',
      borderRight: "1px solid #ccc9b3",
      position: "absolute",
      top: "10px",
      width: "1px",
      right: "0",
      height: "20px",
      bottom: "0"
    },
    "& .MuiInputBase-input": {
      cursor: "pointer",
      width: "calc(100%-20px)"
    }
  },
  autocompleteCustomWithValue: {
    minWidth: "180px",
    position: "relative",
    backgroundColor: "#f0f0eb",
    cursor: "pointer",
    "&::after": {
      display: "none"
    },
    "& .MuiInputBase-input": {
      cursor: "pointer",
      width: "calc(100%-20px)"
    }
  },
  clearIndicatorDirty: {
    backgroundColor: "rgba(0, 0, 0, 0.04)",

    right: "0px"
  },
  clearIndicator: {
    visibility: "hidden"
  },
  searchFieldWidth: {
    whiteSpace: "pre",
    fontSize: "16px",
    visibility: "hidden"
  },
  currentLocationLink: {
    padding: "12px 0 12px 16px",
    borderBottom: "1px solid #0072ff",
    fontSize: "16px",
    fontWeight: "bold",
    color: "#0072ff",
    "&:hover": {
      backgroundColor: "#f0f0eb",
      cursor: "pointer"
    }
  },
  currentLocationLinkMarker: {
    color: "#0072ff"
  },
  autocompleteOption: {
    "& ul li": {
      "&:hover": {
        backgroundColor: "#f0f0eb"
      }
    }
  },
  "@global": {
    '.MuiAutocomplete-option[data-focus="true"]': {
      background: "#f0f0eb"
    }
  },
  listbox: {
    padding: 0
  }
}));

const EmergencyServiceTextField = styled(TextField)`
  .MuiInputLabel-shrink {
    background-color: #ffffff;
  }
  .MuiAutocomplete-endAdornment {
    //right: -20px;
    //right: 10px;
    //top: calc(50%-5px);
  }
  .MuiAutocomplete-inputRoot[class*="MuiInput-root"]
    .MuiAutocomplete-input:first-child {
    padding: 8px 0;
  }
`;

const EmergencyService = React.forwardRef(({ ...props }, ref) => {
  console.log(props, ref);
  const classes = useStyles();
  const [focused, setFocused] = React.useState(classes.autocompleteCustom);
  const [value, setValue] = React.useState(null);
  const [inputValue, setInputValue] = React.useState("");
  const [inputWidth, setInputWidth] = React.useState(autocompleteDefaultWidth);
  const emergencyServiceField = React.useRef();

  const handleChange = (v) => {
    if (v) {
      if ((v !== null) & (v.length > 0)) {
        const thisValue = v.toString().toLowerCase();
        if (thisValue === "yes") {
          setValue("Yes");
          setInputValue("Yes");
        } else if (thisValue === "no") {
          setValue("No");
          setInputValue("No");
        } else {
          setValue(null);
          setInputValue(null);
        }
      }
    }
  };

  React.useEffect(() => {
    if (inputValue !== null && inputValue.length > 0) {
      setFocused(classes.autocompleteCustomWithValue);
      setInputWidth(110);
    }

    /* if (inputValue === 'yes' || inputValue === 'no') {
             setValue(inputValue);
             setInputValue(inputValue);
         }else{
             setValue('test');
             setInputValue('test');
         }
   
         if (value === 'yes' || value === 'no') {
             setValue(value);
             setInputValue(value);
         }else{
             setValue('test');
             setInputValue('test');
         } */
  }, [value, inputValue, inputWidth]);

  return (
    <div
      className={`${focused} ${classes.autocompleteBase}`}
      style={{ width: `${inputWidth}px` }}
      onMouseDown={(event) => {
        event.preventDefault();
        emergencyServiceField.current.focus();
      }}
    >
      <Autocomplete
        disablePortal
        getOptionLabel={(option) =>
          typeof option === "string" ? option : option.label
        }
        options={top100Films}
        autoComplete
        includeInputInList
        filterSelectedOptions
        freeSolo
        openOnFocus
        clearOnBlur
        blurOnSelect
        handleHomeEndKeys
        value={value}
        onChange={(event, newValue) => {
          handleChange(newValue);
        }}
        onInputChange={(event, newInputValue) => {
          handleChange(newInputValue);
        }}
        onFocus={() => {
          setFocused(classes.autocompleteOnFocus);
        }}
        onBlur={() => {
          if (inputValue !== null && inputValue.length > 0) {
            const thisValue = inputValue.toString().toLowerCase();
            if (thisValue === "yes" || thisValue === "no") {
              setFocused(classes.autocompleteCustomWithValue);
            }
          } else {
            setFocused(classes.autocompleteCustom);
          }
        }}
        onKeyDown={(event) => {
          if (event.key !== undefined) {
            if (event.key == "Backspace") {
              if (emergencyServiceField.current.value.length < 2) {
                setValue(null);
                setInputValue(null);
              }
              //console.log('New V = '+emergencyServiceField.current.value);
            }
            // console.log('key' + event.key);
          } else if (event.keyIdentifier !== undefined) {
            console.log("keyId" + event.keyIdentifier);
          } else if (event.keyCode !== undefined) {
            console.log("key Code" + event.keyCode);
          }
        }}
        classes={{
          clearIndicatorDirty: classes.clearIndicator,
          listbox: classes.listbox
        }}
        renderInput={(params) => (
          <EmergencyServiceTextField
            {...params}
            inputRef={emergencyServiceField}
            className={classes.searchField}
            label="Emergency Service"
            fullWidth
            placeholder="Is emergency service required?"
            InputProps={{
              ...params.InputProps,
              disableUnderline: true,
              endAdornment: (
                <IconButton
                  className={clsx(classes.clearIndicator, {
                    [classes.clearIndicatorDirty]:
                      inputValue !== null && inputValue.length > 0
                  })}
                  size="small"
                  onClick={() => {
                    setValue("");
                    setInputValue("");
                  }}
                >
                  <ClearIcon fontSize="small" />
                </IconButton>
              )
            }}
            InputLabelProps={{
              classes: {
                root: classes.inputLabel,
                focused: "focused"
              }
            }}
          />
        )}
      />
    </div>
  );
})

export default EmergencyService;

// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
const top100Films = [
  { label: "Yes", value: "Yes" },
  { label: "No", value: "No" }
];

Upvotes: 1

Ikdemm
Ikdemm

Reputation: 2373

I took a look at your code and I found this error:

SyntaxError
/src/EmergencyService.js: Unexpected token (160:2)

  158 | const EmergencyService = (props, ref) => (
  159 |
> 160 |   const classes = useStyles();
      |   ^

To fix this, you just need to substitute the ( in line 158 and the closing one ) in line 309. This way, you'll get rid of the auto return and you can add javascript code to your functional component. PS: in your current state, the interpreter is expecting JSX code and not JavaScript code since you are in the return statement.

Upvotes: 0

Related Questions