Pass Selected Values to a Get request

Viewed 57

My goal is to pass values selected in a form, to a get request.

The request should look as follows, following submit of the values.

get(api/csv/pets/?columns=DOG&columns=CAT&columns=FISH)

onSubmit={async (values, { resetForm }) => {
    alert(JSON.stringify(values, null, 2));
    setCsvData(values);
    console.log(csvData);  
    const getCsvFile = async (values) => {
      try {
        const { data } = await fetchContext.authAxios.get(
          `/api/csv/pets/${id}/?columns=${csvData ? csvData + '&' : null}`, values);
    
        toCsv(data);
      } catch (err) {
        console.log(err);
      }
    };
    getCsvFile();

However, even though formik takes a payload of values, I still get undefined when placing it in csvData with setCsvData(values).

What can I do to get the values selected in the query, and in the format needed?

My data:

export const CheckList = [
  {
    id: 'column-dog',
    label: 'Dog',
    value: 'DOG',
    name: 'column',
  },
  {
    id: 'column-cat',
    label: 'Cat',
    value: 'CAT',
    name: 'column',
  },
  {
    id: 'column-turtle',
    label: 'Turtle',
    value: 'TURTLE',
    name: 'column',
  },
  {
    id: 'column-fish',
    label: 'Fish',
    value: 'FISH',
    name: 'column',
  },
]

My Form:

enter image description here

const [csvData, setCsvData] = useState([]);
const selectAllData = CheckList.map((checkbox) => checkbox.value);


return (
     <Formik
        initialValues={{
           columns: [],
           selectAll: false,
        }}
        onSubmit={async (values, { resetForm }) => {
          alert(JSON.stringify(values, null, 2));
          setCsvData(values);
          console.log(csvData);
          resetForm();
        }}
        >
         {({ values, setFieldValue }) => (
           <Form>
            <div>
              <Field
                onChange={() => {
                  if (!values.selectAll) {
                    setFieldValue('columns', selectAllData);
                  } else {
                    setFieldValue('columns', []);
                  }
                  setFieldValue('selectAll', !values.selectAll);
                }}
                checked={values.selectAll}
                type="checkbox"
                name="selectAll"
              />{' '}
              Select All
            </div>
    
          {CheckList.map((checkbox) => (
            <div key={checkbox.value}>
              <label>
                <Field
                  type="checkbox"
                  name="columns"
                  value={checkbox.value}
                 />{' '}
                 {checkbox.label}
               </label>
             </div>
           ))}
    
          <button
            className="btn"
            type="submit"
            download
          >
            DOWNLOAD CSV
          </button>
        </Form>
      )}
    </Formik>
)
2 Answers

You cannot use setState inside an async function, becuase setState is an async function itself and it doesn't return a promise. As a result, we can't use async/await for setState method.(If it's not possible to make it await, then state change will trigger right away with undefined values instead of setting the given values)

Please refer this for more info: https://iamsongcho.medium.com/is-setstate-async-b1947fbb25e5

Therefore, the best use case is to remove the async from onSubmit() function to make it synchronous. As a result, setState will trigger the state change in component asynchronously.

Then keep getCsvFile(values), after form reset as you've already done that. And keep getCsvFile() function outside the component, since it doesn't do any state relevant changes.

      onSubmit={(values, { resetForm }) => {
        alert(JSON.stringify(values, null, 2));
        setCsvData(values);
        console.log(csvData);
        resetForm();

        getCsvFile(); // this function will trigger asynchronously
      }}

I think you've over-complicated your code a little bit. Remove csvData from state, and instead pass values into request.

onSubmit={async (values, { resetForm }) => {
    const getCsvFile = async () => {
      try {
        const { data } = await fetchContext.authAxios.get(
          `/api/csv/pets/${id}/?columns=${values ? values + '&' : null}`, values);
        toCsv(data);
      } catch (err) {
        console.log(err);
      }
    };
    getCsvFile();
}

You were getting an error is because the request was firing before csvData was set. setState is asynchronous :)

Related