0

I have a MenuOptions component that I pass an options prop to. Options is a large array of objects. Each object has a nested array called 'services' inside services is an object with a key 'serviceType' which is the only value I want. I want to take all those values, push them into a new array and remove any duplicates if there are any, and then map through that new array and display each item in an 'option' html tag.

here is my createArray function:

    const createNewArray = () => {
        let optionsArr = []
        let uniqueArr;

        options.map((option) => {
            option.services.map((service) => optionsArr.push(service.serviceType))
        })
        uniqueArr = [...new Set(optionsArr)];
        return uniqueArr;
    }

uniqArr seems to be holding what I want but now I want to set this to a piece of global state. Trying something like this does not work. array seems to still be set as null

    const [array, setArray] = useState(null)

   useEffect(() => {
      setArray(createNewArray())
   }, [])

any solutions? Thanks

3
  • I have posted a solution please check it out if it is what you wanted Commented Nov 16, 2021 at 15:35
  • What do you mean by "this does not work" ? Commented Nov 16, 2021 at 15:36
  • Can you show a bit more context? What does MenuOptions definintion look like? Commented Nov 16, 2021 at 15:37

3 Answers 3

1

1) You should add your array state initial value as an empty array:

const [array, setArray] = useState([]);

Live Demo

Codesandbox Demo

2) You can simplify the creating of a new array as:

const createNewArray = () => [
  ...new Set(options.flatMap((o) => o.services.map((obj) => obj.serviceType)))
];

3) set array state in useEffect as:

useEffect(() => {
  setArray(createNewArray());
}, []);
Sign up to request clarification or add additional context in comments.

Comments

0

From your description is this your data?

const options = [{
  services: [
    {
      serviceType: 'serviceType',
    }
  ],
},{
  services: [
    {
      serviceType: 'serviceType',
    }
  ],
},{
  services: [
    {
      serviceType: 'serviceType',
    }
  ],
},
{
  services: [
    {
      serviceType: 'serviceType',
    }
  ],
}]

here is the solution

const uniq = (a) => [...new Set(a)];

const createNewArray = (array) => {
  const c = [...array]
  const newArray = []
  for (let i = 0; i < c.length; i++) {
    const e = c[i];
    for (let ii = 0; ii < e.length; ii++) {
      const ee = e[ii].serviceType;
      newArray.push(ee);
    }
  }
  const toReturn = uniq(newArray)
  return toReturn;
}

3 Comments

Why not just simply, fn = (a) => [...new Set(a)]?
By the looks of it they have a working implementation, they're instead asking about how it isn't rendering
Oh, yeah you are right, this question needs more context
0

If you want unique options, just pass the options in and set them to the state after you massage the data.

const { useEffect, useMemo, useState } = React;

const unique = (arr) => [...new Set(arr)];

const uniqueOptions = (options) =>
  unique(options.flatMap(({ services }) =>
    services.map(({ serviceType }) => serviceType)));

const data = {
  options: [
    { services: [{ serviceType: "Home"  } , { serviceType: "About" }] },
    { services: [{ serviceType: "About" } , { serviceType: "Help"  }] },
    { services: [{ serviceType: "Help"  } , { serviceType: "Home"  }] },
  ],
};

const MenuOptions = (props) => {
  const { options } = props;

  const [opts, setOpts] = useState([]);

  useEffect(() => setOpts(uniqueOptions(options)), [options]);

  return useMemo(
    () => (
      <select>
        {opts.map((opt) => (
          <option key={opt} value={opt}>
            {opt}
          </option>
        ))}
      </select>
    ),
    [opts]
  );
};

const App = ({ title }) =>
  useMemo(
    () => (
      <div>
        <h1>Services</h1>
        <form>
          <MenuOptions options={data.options} />
        </form>
      </div>
    ),
    []
  );

ReactDOM.render(<App />, document.getElementById("react-app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react-app"></div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.