RandString7101610
RandString7101610

Reputation: 3

React Function params are undefined

I am still new to React and am trying to update my api with a fetch request that takes the values provided by my "form". I'm trying to pass in a variable as a parameter to a function but its undefined.

I'm thinking it may be something to do with it being asynchronous but I'm not entirely sure.

import './MakeRequest.css';
import React, { useState , useEffect } from 'react'
import { useLocation } from "react-router-dom";

const MakeRequest = () => {

    const [partySize, setPartySize] = useState(0);
    const [time, setTime] = useState("");
    const [expiration_date, setExpirationDate] = useState("");

    const addRequests = async ({restaurant,partySize,time,expiration_date}) => {
      //values are undefined expect restaurant_name
      console.log(partySize)
      console.log(time)
      console.log(expiration_date)
      let item={"restaurant":restaurant.restaurant_name,"party_size":partySize,"time": time,"expiration_date":expiration_date}
      let result = await fetch("api thingy", {
          method: 'POST',
          headers:{
              "Content-Type":"application/json",
              "Accept":'application/json'
          },
          body:JSON.stringify(item)
          })
      result = await result.json();
    };

    const location = useLocation();
    const restaurant = location.state;

    return (
    <div className = "makeRequest">
        <img src={restaurant.picture} alt="" className="requestpicture"/>
        <h1> Reservation at {restaurant.restaurant_name} </h1>
        <h2> {restaurant.address} </h2>
        <input type = "number"  placeholder = "Party Size"  id = "party-size"
        onChange = {(e)=>setPartySize(e.target.value)}
        className = "form-control"/>
        <input type = "time"  placeholder = "Time"  id = "time"
        onChange = {(e)=>setTime(e.target.value)}
        className = "form-control"/>
        <input type = "date"  placeholder = "Expiration Date"  id = "expiration-date"
        onChange = {(e)=>setExpirationDate(e.target.value)}
        className = "form-control"/>
        {/*
<button onClick={() => console.log(partySize)}> Make Request </button> 
   */}
        <button onClick={() => addRequests(restaurant,partySize,time,expiration_date)}> Make Request </button> 
    </div>
  )}
  export default MakeRequest;

I tried checking to see if for some reason the values are never set in the first place. but when I run the commented code:

<button onClick={() => console.log(partySize)}> Make Request </button> 

I actually receive the right values. Why is this so?

Upvotes: 0

Views: 1497

Answers (1)

ray
ray

Reputation: 27275

You're calling addRequests with 5 arguments, but your function expects a single object.

You could either remove the curlies from the function declaration:

const addRequests = async (restaurant,partySize,time,expiration_date) => {

Or add them to the place where you call it:

onClick={() => addRequests({restaurant,partySize,time,expiration_date})}

Additional Info

Functions that take many arguments can be annoying to use because you have to remember what order to pass them in:

// args must be passed in this order
function addRequests (restaurant, partySize, time, expiration_date) { ... }

To avoid this problem it's common to declare functions that take a single argument, an object with named properties:

function addRequests(options) {}

Declared this way the function can be invoked without having to think about argument order:

const request = {
  partySize: 5,
  expiration_date: new Date(),
  time: '7:00',
  restaurant: {
    name: 'Pizza Chunks',
    address: '999 Chonky Chonk Way'
  }
}

addRequests(request);

The function can then extract the info it needs by name:

function addRequests(options) {
  const time = options.time; // '7:00'
  const partySize = options.partySize; // 5
  ...
}

It can extract a bunch of options at once via destructuring. This is equivalent to the previous snippet:

function addRequests(options) {
  const { time, partySize } = options;
  ...
}

To tighten up the code even further, you can do the destructuring on incoming argument. The function still takes a single argument. We're just extracting properties from that argument. Again, this is equivalent to the examples above.

function addRequests({ time, partySize }) {
  ...
}

shorthand property names

One other thing crucial to understanding the effect the curly braces have when invoking your function is "shorthand property names". When declaring an object literal you can omit the "value" for properties where you'd just be repeating the name:

const partySize = 5;
const time = '7:00';

const options = {
  partySize,
  time,
}

// same as
const options = {
  partySize: partySize,
  time: time,
}

So when you do this (with the curly braces):

addRequests({ restaurant, partySize, time, expiration_date })

You're passing a single argument, an object, with those fields.

Without the curlies you're passing 4 arguments, in a specific order:

addRequests( restaurant, partySize, time, expiration_date )

You can make it work either way, but you have to decide whether the function takes multiple positional arguments or a single options object argument.

You can of course do both if you want:

function someFunc(foo, options) { ... }

someFunc(24, { bing, bang, boom })

Upvotes: 1

Related Questions