1

I have this post method to create a new record in my database:

fetch('https://localhost:44326/api/Players/post', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        handle: data.handle,
        role: data.role,
        avatar: linkToAvatar,
      }),
    })
      .then((response) =>
        console.log(response.json().then((data) => console.log(data.id))),
      )
      .then(() => console.log(newID))
      .then(() => navigate('../Stats/', { state: { userID: newID } }));
  };

This part of that code

.then((response) =>
        console.log(response.json().then((data) => console.log(data.id)))

Gets the response back and logs the id of the newly created record and it works fine.

Above this code, I create a const newID

 const [newID, setNewID] = useState();

In the fetch block if I replace the console.log(data.id) with setNewID(data.id), the value of newID is never set to anything. It remains undefined. Why is this? If the newly created record's id is 80, then newID should be set to 80 there, but it isn't.

This is most of that page in case you need it:

import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import styles from './styles.module.css';
import { useNavigate } from 'react-router';
import S3 from 'react-aws-s3-typescript';
import { config } from '../../config';
import { prototype } from 'events';

type FormData = {
  handle: string;
  role: string;
  avatar: FileList;
};

const ReactS3Client = new S3(config);

function PlayerCreatePage() {
  const navigate = useNavigate();
  const [newID, setNewID] = useState();

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>();

  const onSubmit = (data: FormData) => {
    var avatarName = null;
    var postedName = null;
    if (data.avatar[0]?.name == null) {
      avatarName = null;
      postedName = null;
    } else {
      avatarName = data.avatar[0]?.name;
      postedName = data.avatar[0]?.name;
    }
    var imgType = data.avatar[0]?.name.substr(data.avatar[0]?.name.length - 3);
    if (imgType === 'jpg') {
      postedName = avatarName?.substring(0, avatarName.length - 4);
      avatarName = avatarName?.replace('jpg', 'jpeg');
    } else {
      postedName = postedName?.substring(0, postedName.length - 4);
    }
    var linkToAvatar = null;
    if (avatarName == null) {
      linkToAvatar = null;
    } else {
      linkToAvatar =
        'https://cyberpunkv2.s3.us-east-2.amazonaws.com/avatars/' + avatarName;
    }
    if (postedName != null) {
      ReactS3Client.uploadFile(data.avatar[0], postedName)
        .then((data) => console.log(data))
        .catch((err) => console.error(err));
    }
    fetch('https://localhost:44326/api/Players/post', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        handle: data.handle,
        role: data.role,
        avatar: linkToAvatar,
      }),
    })
      .then((response) =>
        console.log(response.json().then((data) => setNewID(data.id))),
      )
      .then(() => console.log(newID))
      .then(() => navigate('../Stats/', { state: { userID: newID } }));
  };

On the second from bottom line where I log newID it is always 'undefined'. What am I doing wrong or how have I misunderstood the process?

I don't think you need to actually see the render method but if for some reason you do just ask.

EDIT:

Could I not simply do this and forget about the state of newID altogether?

.then((response) =>
      console.log(
        response
          .json()
          .then((data) =>
            navigate('../Stats/', { state: { userID: data.id } }),
          ),
      ),
    );
GrillOwner69420
  • 645
  • 2
  • 5
  • 24
  • 1
    State changes in React are **asynchronous**. React can't reach out and change your `const` `newID` (it's a `const` after all, and React doesn't know it exists so couldn't change it even if it were a `let`). The way your component sees the state change is that React calls your component function again when the change has been made, and provides the new value to you from the `useState` hook (you'll receive it in the new `newID` `const` created by calling the function again). – T.J. Crowder Sep 22 '21 at 15:22
  • Your state `newID` updated asynchronous. You must write `useEffect(()=>{navigate('../Stats/', { state: { userID: newID } })}, [newID])` where state will be updated already. Read more about useState is work. – Vitaliy Rayets Sep 22 '21 at 15:24
  • Consider this simpler example: `function Example() { const [value, setValue] = useState(0); console.log(value); /* <== Logs 0, then 1 */ /* Called only on mount b/c empty deps array: */ useEffect(() => { console.log(value); /* <== Logs 0 */ setValue(1); console.log(value); /* <== Still logs 0! */ }, []); return
    {value}
    ; /* <== Renders
    0
    , then
    1
    */ };` Note that after `setValue(1);`, the `value` constant for that function call is still `0`. But later `Example` is called again and sees `1` from `useState`.
    – T.J. Crowder Sep 22 '21 at 15:25
  • @T.J.Crowder that makes perfect sense now, thank you. How could I alter my code to have newID set to the response body's data.id? – GrillOwner69420 Sep 22 '21 at 16:45
  • @GrillOwner69420 = `setNewID(data.id)` will do that, triggering a new call to your component function. – T.J. Crowder Sep 22 '21 at 16:47
  • @T.J.Crowder I'm a bit confused.. that is precisely what I have in my code already... – GrillOwner69420 Sep 22 '21 at 16:49
  • 1
    Yes, but you also have code looking at the old `newID` immediately afterward, which is the point of my first comment above. That code will always show the **old** `newID` value. If you're not seeing your component function get called again, it suggests that `setNewID` isn't getting called. I suggest stepping back from your current task and building things up slowly in small pieces. – T.J. Crowder Sep 22 '21 at 16:52
  • Ok that makes sense, thank you for the explanation. But perhaps I asked the wrong question. So I have set newID to the correct value there, which is great. Now how do use that NEW value to send to the next page? I don't know how I could call the component function again before navigating to the next page. – GrillOwner69420 Sep 22 '21 at 16:54
  • @T.J.Crowder I'm going to edit my question with a different approach because I can't get it to format correctly here. – GrillOwner69420 Sep 22 '21 at 17:00

0 Answers0