Home > Software design >  In Reactjs, useState not able to setState the data during handleSubmit
In Reactjs, useState not able to setState the data during handleSubmit

Time:12-02

I am trying to figure a silly error, hope someone can help me to understand it better.

setServerList(data.data) doesn't set the data, its still empty when I tried to use it.

export const KernelUpdateSearch = (props: RouteComponentProps) => {
  const [serverList, setServerList] = useState<any>([]);

  // searchHost perform GET request to gannet for aggregate count
  const searchHost = async (hostRegex: string) => {
    try {
      const response = await fetch("URL", {
        mode: 'cors',
        method: 'GET',
        headers: requestHeaders
      });
      const data = await response.json();
      if (data.success === true) {
        if (data.data != null && (data.data.length > 0)) {
          setServerList(data.data);
        } else {
          setServerList([])
          console.log('no data found, status code: ', response.status);
        }
      } else {
          console.log("failed to query, error: ", data.error.message);
      }
    } catch (error) {
        console.log(error);
    }
  };

  const handleSubmit = (formInstance: FormEventReturn) => {
    handleChange(formInstance)
  };

  const handleChange = ({formData}: FormEventReturn) => {
    searchHost(formData.hostname);
    console.log(serverList);
  };

  return (
    <Card options={searchOptions}>
    <Form
      schema={searchSchema}
      uiSchema={uiSchema}
      onSubmit={handleSubmit}
    />
    </Card>
  );
};

CodePudding user response:

How can i setServerList is persistent after handleChang event.

You have two options:

export const KernelUpdateSearch = (props: RouteComponentProps) => {
  const [serverList, setServerList] = useState<any>([]);

  // searchHost perform GET request to gannet for aggregate count
  const searchHost = async (hostRegex: string) => {
    let newServerList = [];
    try {
      const response = await fetch("URL", {
        mode: 'cors',
        method: 'GET',
        headers: requestHeaders
      });
      const data = await response.json();
      if (data.success === true) {
        if (data.data != null && (data.data.length > 0)) {
          newServerList = data.data;
        } else {
          console.log('no data found, status code: ', response.status);
        }

        setServerList(newServerList);
      } else {
        console.log("failed to query, error: ", data.error.message);
      }
    } catch (error) {
        console.log(error);
    }
    //
    // 1a - return new server list
    //
    return newServerList;
  };

  const handleSubmit = (formInstance: FormEventReturn) => {
    handleChange(formInstance)
  };

  const handleChange = ({formData}: FormEventReturn) => {
    searchHost(formData.hostname)
      .then(serverList => {
        //
        // 1b - get returned serverList or empty array
        //
        console.log(serverList);
      });
  };

  //
  // 2 - be notified when there are new servers
  //
  useEffect(() => {
    if (serverList.length > 0) {
       console.log(serverList);
    }
  }, [serverList]);

  return (
    <Card options={searchOptions}>
    <Form
      schema={searchSchema}
      uiSchema={uiSchema}
      onSubmit={handleSubmit}
    />
    </Card>
  );
};

** Edit **

Whether you need serverList as a state variable or not, consider this refactor to make things more readable (i.e. less confusing) :

// ---- utility can be imported from a different module ----

// searchHost perform GET request to gannet for aggregate count
const searchHost = async (hostRegex: string) => {
  let serverList = null;
  try {
    const response = await fetch("URL", {
      mode: 'cors',
      method: 'GET',
      headers: requestHeaders
    });
    const data = await response.json();

    if (data.success === true) {
      if (data.data != null && (data.data.length > 0)) {
        serverList = data.data;
      } else {
        serverList = [];
        console.log('no data found, status code: ', response.status);
      }
    } else {
      console.log("failed to query, error: ", data.error.message);
    }
  } catch (error) {
    console.log(error);
  }

  return serverList;
};

// -------------- React component below -------------

export const KernelUpdateSearch = (props: RouteComponentProps) => {
  const [serverList, setServerList] = useState<any>([]);
    
  const handleSubmit = async ({formData}: FormEventReturn) => {
    searchHost(formData.hostname)
      .then(newServerList => {
        // only update state if the returned value is non null
        if (newServerList) {
          setServerList(newServerList);
        }
      });
  };

  useEffect(() => {
    if (serverList.length > 0) {

       // new servers available!

       console.log(serverList);
    }
  }, [serverList]);

  return (
    <Card options={searchOptions}>
    <Form
      schema={searchSchema}
      uiSchema={uiSchema}
      onSubmit={handleSubmit}
    />
    </Card>
  );
};

Normally, event handlers should be small and simple. Having things inside useEffect is an abstraction that allow you to update the list from any means and have the processing at a central location.

  • Related