Learner
Learner

Reputation: 119

React functional component : can we setState on form load event

react component with hooks:

Requirement: when page load, data populates, from backend, into dropdowns and multi-select tables(tables with checkboxes). On the Submit button click, I need to use this consolidates object (for the default values selected) to make another REST call.

NOTE: No change handler called for any of these ui components.

Issue:

  1. The state is not set at all and if I try to it goes to an infinite loop. as it keeps rendering the page again and again.
  2. if I try to set state and use it, being an async call, the state is not available at that time.

Suggestion needed: is there a way to setState of the default selected values on form load event.

const [data, setData] = useState(undefined);
const changeRequests = useSelector(state => 
  state.oncallRequest.changeRequests
);

useEffect(() => {
  if (!changeRequests.fulfilled) {
    dispatch(fetchRequests(), [dispatch])
      .then(response => setData(setDefaultState(response.data)));
  }
}, [changeRequests.fulfilled, dispatch]);

And I got the below error:

ERROR: TypeError: Cannot read property 'then' of undefined.async call.

Action Class:

export const fetchRequests = () => dispatch => {
    dispatch({type: LIST_PENDING});

    listChangeRequests().then(data => {
        dispatch({type: LIST_FULFILLED, changeRequests: data})
    }).catch(err => {
        dispatch({type: LIST_FAILED, changeRequests: {error: err.message}})
    });
};

**Service Class**
export const listChangeRequests = () => axiosInstance.get(`/getData`).then(res => {
    return res.data;
});

SOLUTION:
I used 2 use Effect: one for fetching data from backend and another for setting state.

**but getting the following exception**
1) **React Hook useEffect has a missing dependency: 'setDefaultState'. Either include it or remove the dependency array**
2) 'data' is assigned a value but never used 

Please advise on the warnings...

    useEffect(() => {
  if (!changeRequests.fulfilled) {
    dispatch(fetchRequests(), [dispatch])
  }
}, [changeRequests.fulfilled, dispatch]);

-------------
useEffect(() => {
        if (changeRequests.data) {
            setData(setDefaultState(changeRequests.data));
        }
    }, [changeRequests.data]);

Upvotes: 0

Views: 9314

Answers (2)

AmerllicA
AmerllicA

Reputation: 32522

Likely, you don't know useEffect, at the initial mounting of your component the useEffect can call an API and then change the state by using useState. like below:

import React, { useState, useEffect } from 'react';

const FormComponent = () => {
  const [data, setData] = useState(undefined);
  const [error, setError] = useState(undefined);

  useEffect(() => {
    // call an API and in the success or failure fill the data by using setData function
    // It could be like below
    ApiCall()
      .then(response => setData(response))
      .catch(err => setError(err))
  }, []);

  ~~~

};

UPDATE

This part is added after your code adding. actually your dispatch function doesn't return Promise event doesn't return anything. so the usage of then in your code is not acceptable and the JavaScript interpreter should return an Error. I guess you should focus on your dispatch function.

Upvotes: 3

Khabir
Khabir

Reputation: 5854

You need to use useEffect and useState Hooks for this.

  useEffect(() => {

     // write any code that will execute at first time

  }, []);  <-- [] is the empty dependency. 

In the below example, LoadUser() function is called in useEffect that will be getting data from api. After successful call, response data is set into the state using setPosts (useState Hook)

import React, { useEffect, useState } from "react";
import axios from "axios";

function ExamplePost() {
  const [isLoading, setIsLoading] = useState(false);
  const [posts, setPosts] = useState([]);
  const [error, setError] = useState("");

  useEffect(() => {
    LoadUser();
  }, []);

  function LoadUser() {
    try {
      setIsLoading(true);
      const response = axios.get(`https://jsonplaceholder.typicode.com/posts`, {
        cancelToken: this.signal.token
      });
      response
        .then((response) => {
          setPosts(response);
          setIsLoading(false);
        })
        .catch((error) => {
          setError(error);
          setIsLoading(false);
        });
    } catch (error) {
      setIsLoading(false);
    }
  }

  return (
    <div>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}
export default ExamplePost;

Upvotes: -1

Related Questions