Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
worms butthole guy
Jan 29, 2021

by Fluffdaddy
thank you all for the above help. I ended up giving up on React and just doing it all in Vue, which seemed to work!

https://sheltered-mesa-21696.herokuapp.com/


Caution: Will autoplay music unless your browser blocks it..


Now I need to figure out how to get transitions to occur between API calls and then play a video as the in-between but i'm happy i've atleast been able to get it up and working lol.

Thanks goons

Adbot
ADBOT LOVES YOU

Combat Pretzel
Jun 23, 2004

No, seriously... what kurds?!
If I do bitwise operations on indexes on an UInt32Array, do I get largely the same semantics as in "proper" typed languages, or will I get hosed by JavaScript number quirks? This is mostly about maintaining a huge bitmap of flags.

Doom Mathematic
Sep 2, 2008
JavaScript bitwise operations coerce all arguments to 32-bit signed integers beforehand and return a new 32-bit signed integer. If you're operating on the members of a UInt32Array then beware. Maximum array length is 2^32 - 1 so if you're operating on indices then, again, beware.

Sab669
Sep 24, 2009

I'm not even sure how to articulate this, but basically I'm wondering if it's possible to "instantiate" an Angular component from a string? Like if I have a component:
code:
@Component({
  selector: 'app-title-page',
  templateUrl: './title-page.component.html',
  styleUrls: ['./title-page.component.css']
})
Then in my main app.component.ts I declare this variable:
code:
public titleComponent: string = "<app-title-page>";
And in app.component.html I have:
code:
<div>
	{{titleComponent}}
</div>
But that just prints out the literal string.

I've also tried:
code:
<div [innerHTML]="titleComponent"></div>
But this just gives me a blank page :(

I feel like this has to be possible but my GoogleFu is failing me

The Merkinman
Apr 22, 2007

I sell only quality merkins. What is a merkin you ask? Why, it's a wig for your genitals!

Sab669 posted:

I'm not even sure how to articulate this, but basically I'm wondering if it's possible to "instantiate" an Angular component from a string? Like if I have a component:
code:
@Component({
  selector: 'app-title-page',
  templateUrl: './title-page.component.html',
  styleUrls: ['./title-page.component.css']
})
Then in my main app.component.ts I declare this variable:
code:
public titleComponent: string = "<app-title-page>";
And in app.component.html I have:
code:
<div>
	{{titleComponent}}
</div>
But that just prints out the literal string.

I've also tried:
code:
<div [innerHTML]="titleComponent"></div>
But this just gives me a blank page :(

I feel like this has to be possible but my GoogleFu is failing me

Do you mean you want to have more control over dynamically loading a component?
If so, look at this example, using createComponent

Sab669
Sep 24, 2009

That sounds like what I'm looking for, yes. Thank you.

LongSack
Jan 17, 2003

Can someone tell me why this doesn't work (or at least didn't work for me, and I spent way too much time on it before going with separate strings rather than an array):
TypeScript code:
const [messages, setMessages] = useState<string[]>([]);
..
async function doCreateVendor() {
  setMessages([]);
...
}
...
{messages.map((x) => (
  <div className="pp__modalmessage" key={x}>{x}</div>
)}
Using setMessages to reset the array to empty did not work. Instead, every pass through the old messages were still there. In addition to there being incorrect messages still in the array, it caused duplicate key messages.

This was in a component which had 2 separate operations, each of which could succeed or fail separately, so my normal use of mui alerts was not appropriate, and I decided to go with a modal dialog with the messages mapped from the array.

I'm using React hooks, version 18

Thanks!

(by the way, the Awful app really doesn't like empty brackets)

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself
we might need some more code/clues for this one. it should be working :confused:

I've had an issue similar to this, but it was around using react-tables which was caching old data and not updating the UI even when the state changed, but this might not be relevant.

Obfuscation
Jan 1, 2008
Good luck to you, I know you believe in hell
I haven’t done React in a while, but I’m guessing that at some point there are duplicate strings in the array which causes the key error and after that the component just shows wrong data

LongSack
Jan 17, 2003

teen phone cutie posted:

we might need some more code/clues for this one. it should be working :confused:

I've had an issue similar to this, but it was around using react-tables which was caching old data and not updating the UI even when the state changed, but this might not be relevant.

I ripped out all the array stuff when I gave up and went with individual strings, but I'll try to reconstruct it here:
TypeScript code:
const [messages, setMessages] = useState<string[]>([]);
const [modalHeading, setModalHeading] = useState<string>('');
...
function addMessage(msg: string) {
  const m = messages || [];
  m.push(msg);
  setMessages([...m]); // I also tried setMessages(m); and setMessages([...messages, msg]);
}
async function doCreateVendor(data: FormData) {
  setModalHeading('');
  setMessages([]);
  const vendor: IVendor = {
    ...data
  };
  if (data.createUser) {
    const user: UserModel = {
      ...data,
      jobTitles: '["Vendor"]',
    };
    const uresult = await createUser(user);
    if (uresult && uresult.ok) {
      addMessage('User created successfully');
    } else if (uresult && !uresult.ok) {
      addMessage(`User creation failed: ${(uresult.body as IApiResponse)?.message}`);
    } else {
      addMessage(`Error creating user (${(uresult.body as IApiResponse)?.code || 0})`);
    }
  }
  const vresult = await createVendor(vendor, true);
  if (vresult && vresult.ok) {
    addMessage('Vendor created successfully');
  } else if (vresult && !vresult.ok) {
    addMessage(`Vendor creation failed: ${(vresult.body as IApiResponse)?.message}`);
  } else {
    addMessage(`Error creating vendor (${(vresult.body as IApiResponse)?.code || 0})`);
  }
  setModalHeading('Vendor Creation Results');
  // @ts-ignore
  modal.showModal();
  resetForm();
}

camoseven
Dec 30, 2005

RODOLPHONE RINGIN'

LongSack posted:

I ripped out all the array stuff when I gave up and went with individual strings, but I'll try to reconstruct it here:
TypeScript code:
const [messages, setMessages] = useState<string[]>([]);
const [modalHeading, setModalHeading] = useState<string>('');
...
function addMessage(msg: string) {
  const m = messages || [];
  m.push(msg);
  setMessages([...m]); // I also tried setMessages(m); and setMessages([...messages, msg]);
}

}

Did you try using something like _.cloneDeep? I have had issues where setting a variable equal to the state array just creates a reference to the state array, so when you manipulate what you think is the copy you're actually manipulating the original and can get all kinds of weird bugs. CloneDeep (and related solutions) create a brand new array in memory, which React likes much better.

e: so like:

code:
const m = messages ? _.cloneDeep(messages) : [];

OR 

const m = messages ? [...messages] : []; // NOTE: only works if the data is not nested!!

camoseven fucked around with this message at 14:45 on May 13, 2022

HexiDave
Mar 20, 2009

LongSack posted:

I ripped out all the array stuff when I gave up and went with individual strings, but I'll try to reconstruct it here:
TypeScript code:
const [messages, setMessages] = useState<string[]>([]);
const [modalHeading, setModalHeading] = useState<string>('');
...
function addMessage(msg: string) {
  const m = messages || [];
  m.push(msg);
  setMessages([...m]); // I also tried setMessages(m); and setMessages([...messages, msg]);
}
async function doCreateVendor(data: FormData) {
  setModalHeading('');
  setMessages([]);
  const vendor: IVendor = {
    ...data
  };
  if (data.createUser) {
    const user: UserModel = {
      ...data,
      jobTitles: '["Vendor"]',
    };
    const uresult = await createUser(user);
    if (uresult && uresult.ok) {
      addMessage('User created successfully');
    } else if (uresult && !uresult.ok) {
      addMessage(`User creation failed: ${(uresult.body as IApiResponse)?.message}`);
    } else {
      addMessage(`Error creating user (${(uresult.body as IApiResponse)?.code || 0})`);
    }
  }
  const vresult = await createVendor(vendor, true);
  if (vresult && vresult.ok) {
    addMessage('Vendor created successfully');
  } else if (vresult && !vresult.ok) {
    addMessage(`Vendor creation failed: ${(vresult.body as IApiResponse)?.message}`);
  } else {
    addMessage(`Error creating vendor (${(vresult.body as IApiResponse)?.code || 0})`);
  }
  setModalHeading('Vendor Creation Results');
  // @ts-ignore
  modal.showModal();
  resetForm();
}

If you're just adding to existing state, use some form like this:

TypeScript code:
function addMessage(msg: string) {
    setMessages(previousState => [...previousState, msg])
}
Granted, I'm not sure why your function is failing the way it is - the "setMessages([...messages, msg])" should work as it's creating fresh state.

LongSack
Jan 17, 2003

Yeah, I spent way too much time banging my head against it before finally giving up and moving on. Oh well, what I have now works just fine, so ...

Also, is there an equivalent CSS shorthand property like margin-inline that sets the top and bottom margins? I can't seem to frame my google queries properly and all I'm getting is references to the four standard "margin-xxx" properties. I think the left/right and top/bottom shorthands are pretty new, since VS Code doesn't highlight them properly, but they do work (except in IE, of course).

teen phone cutie
Jun 18, 2012

last year i rewrote something awful from scratch because i hate myself
CSS code:
.element {
  margin: 10px 0;
}
or

CSS code:
.element {
  margin: 10px 0 5px 0;
}
The first example handles both top and bottom at 10px and right and left at 0px, while the second example goes top, right, bottom, left

e: oh lol i misunderstood the question sorry

teen phone cutie fucked around with this message at 22:04 on May 13, 2022

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

LongSack posted:

Yeah, I spent way too much time banging my head against it before finally giving up and moving on. Oh well, what I have now works just fine, so ...

Also, is there an equivalent CSS shorthand property like margin-inline that sets the top and bottom margins? I can't seem to frame my google queries properly and all I'm getting is references to the four standard "margin-xxx" properties. I think the left/right and top/bottom shorthands are pretty new, since VS Code doesn't highlight them properly, but they do work (except in IE, of course).

margin-inline / margin-inline-start / margin-inline-end = horizontal

margin-block / margin-block-start / margin-block-end = vertical

LongSack
Jan 17, 2003

Thank you.

fakemirage
Nov 6, 2012

Can't see the haters.

HexiDave posted:

Granted, I'm not sure why your function is failing the way it is - the "setMessages([...messages, msg])" should work as it's creating fresh state.
messages won't actually contain the value you expect in this case (see https://dev.to/adamklein/we-don-t-know-how-react-state-hook-works-1lp8#the-update-queue-and-lazy-computation).
JavaScript code:
console.log(messages); // ["foo", "bar"]
setMessages([]);
console.log(messages); // ["foo", "bar"]
So using messages as the basis of your new state can create some weird results.
JavaScript code:
console.log(messages); // ["foo", "bar"]
setMessages([]);
setMessages([...messages, "hello world"]); // = setMessages(["foo", "bar", "hello world"])
So your recommendation to use previousState would probably have fixed the issue.

LongSack
Jan 17, 2003

fakemirage posted:

messages won't actually contain the value you expect in this case (see https://dev.to/adamklein/we-don-t-know-how-react-state-hook-works-1lp8#the-update-queue-and-lazy-computation).
JavaScript code:
console.log(messages); // ["foo", "bar"]
setMessages([]);
console.log(messages); // ["foo", "bar"]
So using messages as the basis of your new state can create some weird results.
JavaScript code:
console.log(messages); // ["foo", "bar"]
setMessages([]);
setMessages([...messages, "hello world"]); // = setMessages(["foo", "bar", "hello world"])
So your recommendation to use previousState would probably have fixed the issue.

That describes exactly the behavior i was seeing, so thanks. I’ll read up on those links.

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
Is there a way to detect whether a stream has been written to?

code:
stream.write('hello');

// etc...

if (stream.anythingWrittenToStream) { ... }
Specifically looking at cases where the stream has been written to but ".end()" hasn't been called yet. So peeking "stream.writableEnded" isn't it. I tried "stream.writableLength" but I'm misunderstanding what that's for since for me it's always 0.

Tea Bone
Feb 18, 2011

I'm going for gasps.
I've created a PWA with react.

I've installed the app to my phone (android) but as soon as the splash screen clears it launches the app in chrome rather than stand-alone. I've tried it in an android emulator and everything works great there. I also have other PWAs on my phone and they work as expected so I suspect it's some kind of configuration I've missed?

The Merkinman
Apr 22, 2007

I sell only quality merkins. What is a merkin you ask? Why, it's a wig for your genitals!

Tea Bone posted:

I've created a PWA with react.

I've installed the app to my phone (android) but as soon as the splash screen clears it launches the app in chrome rather than stand-alone. I've tried it in an android emulator and everything works great there. I also have other PWAs on my phone and they work as expected so I suspect it's some kind of configuration I've missed?

I'm not familiar with React, but what does the manifest.json look like?

Tea Bone
Feb 18, 2011

I'm going for gasps.
Thanks, it's just the standard manifest that's generated by create-react-app:

code:
{
  "short_name": "MyPwa",
  "name": "MyPwa",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    },
    {
      "src": "logo192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "logo512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

The Merkinman
Apr 22, 2007

I sell only quality merkins. What is a merkin you ask? Why, it's a wig for your genitals!

Tea Bone posted:

Thanks, it's just the standard manifest that's generated by create-react-app:

code:
{
  "short_name": "MyPwa",
  "name": "MyPwa",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    },
    {
      "src": "logo192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "logo512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

It's hosted somewhere via https right? Can you run it through Google Lighthouse, specifically the PWA section, to see if something is missing there?

Tea Bone
Feb 18, 2011

I'm going for gasps.

The Merkinman posted:

It's hosted somewhere via https right? Can you run it through Google Lighthouse, specifically the PWA section, to see if something is missing there?

Ah this might be it. No, I'm still running it off local host at the moment and setting the 'treat as secure' flag in chrome. Thanks for your help.

Armitag3
Mar 15, 2020

Forget it Jake, it's cybertown.


Nolgthorn posted:

Is there a way to detect whether a stream has been written to?

code:
stream.write('hello');

// etc...

if (stream.anythingWrittenToStream) { ... }
Specifically looking at cases where the stream has been written to but ".end()" hasn't been called yet. So peeking "stream.writableEnded" isn't it. I tried "stream.writableLength" but I'm misunderstanding what that's for since for me it's always 0.

stream.write() will return a boolean when called. If you declare a null or undefined variable first and assign the value of stream.write() to it, as long as the value is boolean you’ll know something was written.

JavaScript code:
let isWritten = null;

// etc…

isWritten = stream.write('hello');

// etc...

if (isWritten !== null) { ... }

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
Usage of `.write` is out of my hands, that's why I want to check the stream object directly. The purpose is for my webapp library, I want to handle cases where the developer wrote something to the outgoing stream but didn't call `.end` for any reason.

I guess there's no way to do it.

The downside to not being able to check is the 'Content-Length` header being set to `0` and the status code being changed from `200` to `204`, even though there might be a body that was sent to the client.

Probably not too big a deal.

Nolgthorn fucked around with this message at 21:53 on May 18, 2022

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Make a wrapper object around the outstream that does these checks instead of passing around the outstream directly.

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense

Jabor posted:

Make a wrapper object around the outstream that does these checks instead of passing around the outstream directly.

That would make sense, completely. Unfortunately I'm a stick in the mud and I specifically want not to touch any of the native node tools. Your solution makes perfect sense I'm just not gonna do it.

I'll maybe mention it in the documentation to "hold the phone correctly" so to speak.

ynohtna
Feb 16, 2007

backwoods compatible
Illegal Hen
Would using a Proxy object for the stream wrapper be an option?

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
Node doesn't seem to want us to be able to inspect what's going on with a stream, maybe there's a good reason for that. If I start checking the `write()` method for use then I should also check `pipe()` or so on... I don't actually know how many ways there are to write to a stream.

That might be all.

It feels like it gets hairy, I just don't like hacky code. If a stream is meant to be an enigma then so it is, as long as I'm not working for someone who tells me differently.

LongSack
Jan 17, 2003

Not sure whether to put this question here, the front-end thread, of the web development thread, but I figure I'll start here.

I have a React app that I just moved to an Azure web app host. The problem is that I'm using Auth0 for authentication, and Auth0 needs direct access to two URIs: /signin-callback and /signout-callback.

It works locally when redirecting to localhost:3000/signin-callback, for example, but when trying the same thing to the Azure URL (https://jimcoemployeeportal.azurewebsites.net/signin-callback) it fails with a 404.

I should note that this happens if I try to directly access any path other than "/". If I go there "internally" (say via <Link /> or useNavigate()) everything works great. Even on the employee portal, you can click either button on the "/" page (About or Disclaimer) and it navigates just fine, but if I try to navigate directly to /About it also 404s.

I understand, I think, why it's happening - the "pages" in react aren't really pages in the traditional HTML sense, but I need a workaround.

Google is telling me I need to do something with a web.config, but those answers are several years old, and I don't know if they are still applicable, and if so exactly what I need to put in there.

Any ideas? Thanks.

minato
Jun 7, 2004

cutty cain't hang, say 7-up.
Taco Defender
In a vanilla web page, when you click a link then the browser sends that URL to the web server and returns a response. However in a React Single-Page-App with routes configured, the React SPA will intercept the URL change event to scan the link to see if it matches a known route, and if it finds a match then the router code will update the browser page + URL client side, and no request is sent to the web server. (If there's no match then it gets sent to the web server as normal).

So if you visit "/myapp/someroute" before the SPA is loaded, the SPA has no chance to intercept the request and render the page locally. The web server will be sent the "/myapp/someroute" request, and it'll shrug and give you a 404 because it doesn't know anything about that URL. If you visited "/" beforehand, then the SPA is loaded and intercepts the "/myapp/someroute" link click, and it works.

To make it so "/myapp/someroute" works regardless of whether the SPA is loaded or not, you need to configure your webserver so that if it receives a request for either "/" or "/myapp/someroute" (or any other possibly SPA route), the server will respond with the same HTML/JS that loads your SPA. And the first thing your SPA should do when it loads is parse the current URL (don't assume it's "/") and render the appropriate sub-page.

Your webserver config will need to look like:
1. If the URL matches "/sign-in-callback", return the "/sign-in-callback" HTML page
2. If the URL matches "/sign-out-callback", return the "/sign-out-callback" HTML page
3. Anything else, return the contents of "load_my_spa.html".

Edit: on re-reading, it sounds like your "/sign-in-callback" and "/sign-out-callback" are also sub-pages within your SPA, in which case you can ditch (1) and (2) in the steps above and just have a simple blanket URL pattern match that always loads your SPA.

minato fucked around with this message at 19:53 on May 20, 2022

LongSack
Jan 17, 2003

minato posted:

3. Anything else, return the contents of "load_my_spa.html".

And is this done in web.config? I've seen reponses that say to use this for a web.config:
XML code:
<configuration>
<system.webServer>
    <rewrite>
      <rules>
        <rule name="Main Rule" stopProcessing="true">
                <match url=".*" />
                <conditions logicalGrouping="MatchAll">
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                </conditions>
                <action type="Rewrite" url="/" />
            </rule>
        </rules>
    </rewrite>
</system.webServer>
</configuration>
This looks like it's rewriting URLs but neither of the examples listed (file, directory) look like a match. I'm not really handy with the operation and configuration of the actual web servers, and the few times I have messed with it it's been Apache, so IIS is a whole new thing.

That is to say, I don't know what to put in web.config to accomplish what I need to do.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

LongSack posted:

This looks like it's rewriting URLs but neither of the examples listed (file, directory) look like a match. I'm not really handy with the operation and configuration of the actual web servers, and the few times I have messed with it it's been Apache, so IIS is a whole new thing.
I'm not familiar with this form of config, but it looks to me like negate=true means "don't do this action when these conditions are met", i.e. rewrite to / if the given path *doesn't* point at a file or directory. Which it seems like is what you want.

LongSack
Jan 17, 2003

roomforthetuna posted:

I'm not familiar with this form of config, but it looks to me like negate=true means "don't do this action when these conditions are met", i.e. rewrite to / if the given path *doesn't* point at a file or directory. Which it seems like is what you want.

FWIW, adding that web.config to the public directory fixed the problem.

Rockybar
Sep 3, 2008

I'm trying to write a function which will automatically update components based on a firebase realtime database updating. This is so two people could work on something simultaneously (a workout builder). The issue I'm running into is that each 'onValue' triggers a re-render, which re-triggers 'onValue' etc.. I've tried wrapping the onValue in a useEffect, which works but means it only updates once and doesn't 'setData' on a change. So I'm trying this which is very bodgy, but while it doesn't trigger an infinite loop it's not updating 'data', although I can see in the logs that it's returning the updated data on the value change. Any help appreciated if there's a more logical way to do this.

JavaScript code:
const app = initializeApp(firebaseConfig);
const db = getDatabase(app);
const workouts = ref(db, "workouts/");
let dataNew = [];
let dataOld = [];
let initial = true;

function Workouts() {
  const [data, setData] = useState([""]);

  onValue(workouts, (snapshot) => {
    dataNew.length = 0;
    console.log("new update");
    snapshot.forEach(function (userSnapshot) {
      const userData = userSnapshot.val();
      dataNew.push(userData);
    });

    if (dataNew !== dataOld) {
      console.log("Date New: " + dataNew);
      setData(dataNew);
      dataOld = dataNew;
      initial = false;
      console.log("updated. data: " + data);
    }
  });

  return (
    <div>
      {data.length !== 0 ? (
        data.map((item) => <div>{JSON.stringify(data)}</div>)
      ) : (
        <div>No Data</div>
      )}
    </div>
  );
}
export default Workouts;

reversefungi
Nov 27, 2003

Master of the high hat!

Rockybar posted:

I'm trying to write a function which will automatically update components based on a firebase realtime database updating. This is so two people could work on something simultaneously (a workout builder). The issue I'm running into is that each 'onValue' triggers a re-render, which re-triggers 'onValue' etc.. I've tried wrapping the onValue in a useEffect, which works but means it only updates once and doesn't 'setData' on a change. So I'm trying this which is very bodgy, but while it doesn't trigger an infinite loop it's not updating 'data', although I can see in the logs that it's returning the updated data on the value change. Any help appreciated if there's a more logical way to do this.

JavaScript code:
const app = initializeApp(firebaseConfig);
const db = getDatabase(app);
const workouts = ref(db, "workouts/");
let dataNew = [];
let dataOld = [];
let initial = true;

function Workouts() {
  const [data, setData] = useState([""]);

  onValue(workouts, (snapshot) => {
    dataNew.length = 0;
    console.log("new update");
    snapshot.forEach(function (userSnapshot) {
      const userData = userSnapshot.val();
      dataNew.push(userData);
    });

    if (dataNew !== dataOld) {
      console.log("Date New: " + dataNew);
      setData(dataNew);
      dataOld = dataNew;
      initial = false;
      console.log("updated. data: " + data);
    }
  });

  return (
    <div>
      {data.length !== 0 ? (
        data.map((item) => <div>{JSON.stringify(data)}</div>)
      ) : (
        <div>No Data</div>
      )}
    </div>
  );
}
export default Workouts;

Not familiar with the onValue that seems be coming from firebase, so there might be something that needs to be figured out with that and useEffect. However, this line is suspect:

code:
if (dataNew !== dataOld)
Those are both arrays, so you are comparing their references, so this if block will always run, since dataNew !== dataOld will always evaluate to true.

LongSack
Jan 17, 2003

I apologize in advance the the length of this post.

I have a react app hosted on azure app service. It uses Auth0 for authentication. It works as expected on any desktop I've tried: Windows, Mac Catalyst, even Open-SUSE Linux.

It does not work on any mobile device. I've tried my iPhone, iPad and even my office television (it's an android device with a web browser).

What appears to happen is that in my authorization context, it hits a certain line and just stops. No error message, nothing on the console, it just ... stops. Trimmed code below:
TypeScript code:
import React, {
  createContext,
  ReactNode,
  useContext,
  useEffect,
  useState,
} from 'react';
import createAuth0Client from '@auth0/auth0-spa-js';
import Auth0Client from '@auth0/auth0-spa-js/dist/typings/Auth0Client';
import { UserModel } from '../Interfaces/UserModel';
import { Auth0User } from '../Interfaces/Auth0User';
import { getUserModel } from '../Services/UserService';
import { authSettings } from '../AppSettings';
import { log } from '../Services/LogService';
import { Level } from '../Services/tools';

interface IAuth0Context {
  isAuthenticated: boolean;
  user?: Auth0User;
  userModel?: UserModel;
  signIn: () => void;
  signOut: () => void;
  loading: boolean;
}

export const Auth0Context = createContext<IAuth0Context>({
  isAuthenticated: false,
  signIn: () => {},
  signOut: () => {},
  loading: true,
});

export const useAuth = () => useContext(Auth0Context);

export const AuthProvider: React.FC<{ children: ReactNode }> = ({
  children,
}) => {
  const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
  const [user, setUser] = useState<Auth0User | undefined>(undefined);
  const [userModel, setUserModel] = useState<UserModel | undefined>(undefined);
  const [auth0Client, setAuth0Client] = useState<Auth0Client>();
  const [loading, setLoading] = useState<boolean>(true);

  const getClientFromState = () => {
    if (auth0Client === undefined) {
      throw new Error('Auth0 client is not set');
    }
    return auth0Client;
  };

  useEffect(() => {
    const initAuth0 = async () => {
      console.log('In InitAuth0'); // THIS LOGS
      setLoading(true);
      console.log('Loading set true'); // THIS LOGS
      console.log(JSON.stringify(authSettings, undefined, 2)); // THIS LOGS
      const auth0 = await createAuth0Client(authSettings); // Apparently, the code stop here or else the promise never resolves? 
      console.log('auth0 retrieved'); // THIS DOES NOT
      await log(Level.DEBUG, 'Auth0', 'Auth0 Client', auth0);
      setAuth0Client(auth0);
      if (
        window.location.pathname === '/signin-callback' &&
        window.location.search.indexOf('code=') > -1
      ) {
        await auth0.handleRedirectCallback();
        window.location.replace(window.location.origin);
      }
      const isAuthenticated = await auth0.isAuthenticated();
      await log(Level.DEBUG, 'Auth0', 'Is Authenticated', isAuthenticated);
      if (isAuthenticated) {
        const user = await auth0.getUser<Auth0User>();
        setUser(user);
        await log(Level.DEBUG, 'Auth0', 'Auth0 user', user);
        const model = await getUserModel(user, await getToken());
        if (model) {
          await log(Level.DEBUG, 'Database', 'User model', model);
          setUserModel(model);
        }
      }
      setIsAuthenticated(isAuthenticated);
      setLoading(false);
    };
    console.log('In UseEffect'); // THIS LOGS
    initAuth0();
  }, []);

  return (
    <Auth0Context.Provider
      value={{
        isAuthenticated,
        user,
        userModel,
        signIn: () => getClientFromState().loginWithRedirect(),
        signOut: () =>
          getClientFromState().logout({
            client_id: authSettings.client_id,
            returnTo: window.location.origin + '/signout-callback',
          }),
        loading,
      }}
    >
      {children}
    </Auth0Context.Provider>
  );
};
I never see any hits in my Auth0 logs from this, and am at a loss as to how to proceed to try to figure out what's going on. Any ideas?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
If you create a new Auth0Client via the constructor and call getTokenSilently yourself, instead of using createAuth0Client, does that give you more insight into which part is breaking?

Adbot
ADBOT LOVES YOU

Rockybar
Sep 3, 2008

The Dark Wind posted:

Not familiar with the onValue that seems be coming from firebase, so there might be something that needs to be figured out with that and useEffect. However, this line is suspect:

code:
if (dataNew !== dataOld)
Those are both arrays, so you are comparing their references, so this if block will always run, since dataNew !== dataOld will always evaluate to true.

Thanks, this was one issue out of a few. Took a few hours of head scratching but came up with this solution:

JavaScript code:
  useEffect(() => {
    onValue(workouts, (snapshot) => {
      data2.length = 0;
      snapshot.forEach(function (userSnapshot) {
        const userData = userSnapshot.val();
        data2.push(userData);
      });

      if (JSON.stringify(data2) !== JSON.stringify(data)) {
        setData([...data2]);
        console.log("update " + renders);
      }
    });
  }, [onValue]);
Setting the new state needed to be [...data2] instead of [data] to prompt the re-render. Can't say it's the most efficient comparing two massive strings but it works for now and I can move on...

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply