Home > database >  How to use useState and useEffect over array
How to use useState and useEffect over array

Time:03-28

In the code below, I have a few textareas where the user should input jsons.

I tried to use and array (well, object with numeric keys, just for the ease from rest operator assignment), and I also wanted to avoid parsing both JSONs at every change of either.

It works well, except that for the first render, I get validation only on the second json. I am pretty sure it comes down to scope, with old values being stored in the useEffect, but I added the callback versions of setErrors and that didn't work.

What am I doing wrong, and what is the right pattern for this?

PS: I intend to move each textarea into individual components of course, but would like to understand what is wrong here first.

  const [jsons, setJsons] = useState<{ [k: number]: string }>({ 0: '', 1: '' });
  const [containers, setContainers] = useState<{ [k: number]: object }>({ 0: {}, 1: {} });
  const [errors, setErrors] = useState<{ [k: number]: string }>({ 0: '', 1: '' });

  const useContainerEffect = (index: number) => {
    useEffect(() => {
      let container = {};
      try {
        container = JSON.parse(jsons[index]);
        setErrors(() => ({ ...errors, [index]: '' }))
      } catch (e) {
        setErrors(() => ({ ...errors, [index]: VALUE_IS_NOT_JSON }))
      }
      setContainers(() => ({ ...containers, [index]: container }))

    }, [jsons[index]]);
  }

  useContainerEffect(0);
  useContainerEffect(1);

  const jsonInputChange = (e: HTMLTextAreaElement, i: number) => {
    setJsons({ ...jsons, [i]: e.value })
  }

CodePudding user response:

Try using functional form of useState to set your errors. Also it's a good practice not to use complex dependencies in dependency array, so they can be statically checked:

  const useContainerEffect = (index: number) => {
    useEffect(() => {
      let container = {};
      try {
        container = JSON.parse(jsons[index]);
        setErrors((err) => ({ ...err, [index]: '' }));
      } catch (e) {
        setErrors((err) => ({ ...err, [index]: 'VALUE_IS_NOT_JSON' }));
      }
      setContainers(() => ({ ...containers, [index]: container }));
    }, [index]);
  };
  • Related