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
Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

LifeLynx posted:

I'm trying and failing to get the background color of a page to change when an element is scrolled into view. All of these .fullheight sections have min-height: 100vh.
This does exactly what I want, but I want to do it in vanilla JS: https://codepen.io/daveredfern/pen/zBGBJV

IntersectionObserver is an alternative to using a scroll event handler, so you can get rid of that. Instantiating a new observer on every scroll event sounds like a performance nightmare.

You're also setting the background color on every iteration of entries, so only the intersecting status of the last entry will ever change the background color.

Without setting a threshold and with 100vh elements, you'll also have different sections competing for who sets the background color, so maybe try 50%?

And you can probably save yourself some if statements by storing the color directly in the data attribute.

code:
<section class="fullheight color-target" data-color="#ffffff">Default</section>
<section class="fullheight color-target" data-color="#009900">Green</section>
<section class="fullheight color-target" data-color="#990000">Red</section>
<section class="fullheight color-target" data-color="#000099">Blue</section>
<script type="text/javascript">
let prevColor;

const observer = new IntersectionObserver(entries => {
  let nextColor = '#ffffff';

  entries.forEach(entry => {
    if (entry.isIntersecting) {
      nextColor = entry.target.getAttribute('data-color');
    }
  });

  if (nextColor !== prevColor) {
    prevColor = nextColor;
    document.body.style.backgroundColor = nextColor;
  }
}, { threshold: 0.5 });

document.querySelectorAll('.color-target').forEach(image => {
  observer.observe(image);
});
</script>

Adbot
ADBOT LOVES YOU

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

roomforthetuna posted:

If you're doing that kind of thing, please try to avoid doing the all too common lovely thing that sites do these days, where because you make the site out of dynamic components and junk, you forget how internet navigation is supposed to work and lose all the back/forward history navigation, ability to send a link to what you're looking at to a friend, etc.

If you're doing dynamic content, you should make it so the URL always contains all the information to get back to the same content (except for, like, an acknowledgment of an update action or a user-specific shopping cart contents), and make it so when the user navigates within the site, the views they pass through are reflected in the DOM history.
Given how with Next.js, you're tied into their routing and data-fetching system, it'd be pretty hard to gently caress it up in the way that you're describing.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Empress Brosephine posted:

You can force it to have a onClick by setting it to that one weird thing.
You shouldn't need to do this though? The browser already knows how to trigger a submit event on the parent <form> when someone clicks a submit button.

Empress Brosephine posted:

TBH I’m not a fan of Formik and only used it because of a weird tutorial I was following. I would like to strip Formik and MaterialUI out; they both seem too complex for what I need. I know others have suggested React Select, but is there a good way to handle forms in Next/React other than Formik?
I would recommend trying to get away from the render-prop pattern (passing a callback function as a child to some component). Using the hook functions from Formik instead will make your experience as lot better/less messy. Alternatively, you could look into React-Hook-Form or React-Final-Form. The experience isn't that much different between them though. :shrug:

Regarding custom select dropdowns, React-Select is not the most flexible library, but it's tried and true. Downshift is another popular option worth looking at.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Chas McGill posted:

Running into rerender nonsense with contexts that have become too large/interdependent. Before I reach for redux, are any of the newer state management libraries worth checking out? Performance is probably the main aim.

Before ripping up everything to switch to a state management library, you might want to try this useContextSelector hook library that lets you use contexts with selectors to isolate re-renders.

Based on some recent PR's (1, 2) it looks like a similar API might show up as an experimental feature in react soon too.

Ima Computer fucked around with this message at 00:56 on Mar 5, 2021

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
React is entirely built around the idea of unidirectional top-down data flow. Accessing a child component's properties is a big anti-pattern and red flag. If you find yourself wanting to communicate back up the component tree, in most cases, pulling state up is the most appropriate solution. For the rare instances when you really need to communicate child state updates back up the tree, escape hatches exist: passing callback functions as props, using context, or bringing in a state management library like redux (yuck, don't do this). I'm getting big XY problem vibes here though.

Ima Computer fucked around with this message at 17:29 on Apr 5, 2021

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Empress Brosephine posted:

Any of you have experience with apollo and wpgraphql? Or I guess NextJs in general. I have a odd question that no one's answered on stack overflow yet and goons usually know their stuff. Thanks


https://stackoverflow.com/questions/67291378/nextjs-apollo-wpgraphql-combining-or-retrieving-more-than-100-records

dataset2 is undefined because dataset2 isn't a property you get back from calling client.query().

I think you meant to rename the data property instead?

JavaScript code:
const { data: dataset2 } = await client.query({
  // ...
});
Also, I would recommend defining your queries in a separate file, or at least at module scope level, instead of defining them inside of getStaticProps, for better readability and to avoid re-compiling the strings into queries on every call.

Ima Computer fucked around with this message at 04:28 on Apr 28, 2021

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Combat Pretzel posted:

What I was doing so far was creating a state variable called rt (for runtime, because ???) and doing rt.var = ... instead of the this.var = ... previously in a class. Seemed to work fine. So far anyway.

Storing values as instance properties on a class component (this.var = ...) is something you should only be doing if you explicitly do not want changes to that value to trigger your component to re-render. If this is really what you need, you should be using useRef() in your functional component to create a persistent reference to an object where you can store those values.

This really isn't a very common use case to run into though. In the majority of cases, you do want state changes to trigger re-renders.

In class components, this is done by calling the .setState() method of the component instance.

For functional components (the best components) you should be using the useState hook and using the setter function it returns to update your state value(s).

I would recommend reading the documentation for react hooks before proceeding further with converting your components.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
It's a bad practice to make a request to a URL that produces HTML markup in the first place, since it means you have to scrape the actual content you want out of the markup.

It's also dangerous to write the contents of the response as HTML to your page in order to "parse" it. Doing so opens you up to potential code execution attacks, such as if there is a script tag present (and there are numerous other ways to trigger script execution without a script tag too)

If there's really no way around making a request to a page full of HTML, there are better and safer ways to accomplish it, like the DOMParser API:

JavaScript code:
(async () => {
  // fetch the html as a string
  const response = await fetch('/get-titles/');
  const responseText = await response.text();
 
  // parse the html into an HTMLDocument without writing it to the page
  const parser = new DOMParser();
  const responseDocument = parser.parseFromString(responseText, 'text/html');
  
  // query-select all the <li> tags and extract their innerText to store in an array
  const titles = Array.from(responseDocument.querySelectorAll('li')).map((el) => el.innerText);
 
  // log output
  console.log(titles);
})();

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Defining a CSS custom property inside a style prop object seems to work just fine?

https://codesandbox.io/s/quiet-snowflake-eiws1?file=/src/App.js

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

huhu posted:

I want to fetch the data, with GET_DATA, that is needed for the Foo component. If the data doesn't exist, I want to use ADD_DATA to create the data and then get back the result.
Maybe I'm confused about your use case, but this sounds like logic that should go on the server-side/GQL/API layer, not in the client side app?

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

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
https://www.youtube.com/watch?v=Uo3cL4nrGOk

quote:

My job is to keep our code running while other packages are changing theirs.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
I like using Object.entries to convert the object into an array of key-value pairs, doing whatever manipulation I want, then rebuilding the object with Object.fromEntries:
TypeScript code:
const removeManyKeys = <T extends Record<string, unknown>>(thing: T, removeMany: (keyof T)[]) =>
  Object.fromEntries(
    Object.entries(thing).filter(([key]) => !removeMany.includes(key))
  ) as Omit<T, typeof removeMany[number]>;

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Deadite posted:

What does this mean? Should I not be doing the parent/child/props thing? I have no idea what I'm doing so if there's a better way I'd like to learn that.

Check out the beta docs/tutorials - they use function components instead of classes, which is the way (almost) all React code is written these days.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

fuf posted:

So it feels like I've come full circle. If I'm still using context providers then why would I use zustand rather than just storing the state directly in the context like I was before?

The motivation for moving to zustand was to try and avoid the issue where components using a context provider have to re-render every time anything in the context changes. I'm assuming that if the context contains a zustand store then all the components are going to re-render when the store changes?

As long as you're memoizing the newly instantiated zustand store at the Provider level, the reference to the store never changes, so the context won't cause a re-render (unless you redefine/recreate your store)

If you have global state which doesn't need multiple instances, then you don't need to use a Context at all, since all consumers can share a direct import reference to the same instance of the store.

Ima Computer fucked around with this message at 14:53 on Mar 8, 2023

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

death cob for cutie posted:

Why can I put multiple strings inside the brackets here? Obviously the behavior is that it returns the value associated with the last key (assuming it exists), but why does the interpreter even accept multiple arguments for whatever function is actually called (this is where I think I'm not finding the right thing) when I use square brackets here?

You can put any JS expression you want inside a property accessor that uses square brackets syntax.

The "evaluates to last value" behavior is just how the comma operator works.

Its rules apply any time you shove a comma somewhere you wouldn't normally expect to see one.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Vino posted:

but misses some that I have stored in strings

Why are you storing variable/function names in strings? That's a pretty abnormal thing to do.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
I agree with Osmosisch that the performance issues are probably caused more by rendering 800 expensive components (which you can solve with virtualization/windowing and/or memoization) than by how you're managing immutable updates to the array.

Using an object as a map is a significantly worse solution here though, especially if maintaining the order of items in the list is important. It also means you have to call Object.entries() on every render before you can iterate over the items, which is going to have higher rendering computation cost and memory usage in comparison to just using an array in the first place.

This is a problem space that's solved pretty nicely by atomic state management libraries like Recoil and Jotai. The splitAtom utility from Jotai especially seems like it would be a good fit here.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
I'm not sure if using an object as a map would actually help troubleshoot the issue.

Cloning an object and overwriting a property isn't really that much different from cloning an array and swapping one of its elements. It still gives you a new reference and it still requires a loop - its just a loop that's hidden behind syntax sugar (the object spread) and which iterates over a list of string keys instead of array indices.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
It's 2024. The war is over. TypeScript won. Every library nowadays either provides first-class support for TypeScript or has mature community-developed type definitions.

If your projects haven't at least partially adopted TypeScript yet, that's a sign of neglect.

Harriet Carker posted:

Can anyone help me maybe understand what he means? I've never run into this issue and I'm super unclear, but I don't feel confident enough to engage in the discussion.

Sounds odd. If you're using webpack, you shouldn't need to worry about that ESM<->CJS interop nonsense anyway. :shrug: The bundler should be normalizing all the modules while it's stitching them together into bundles. Modern versions of typescript support all sorts of different module resolution options - one of them has to match the behavior of your bundler.

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Sad Panda posted:

When I tick a task in the ShowTodosForm, the count goes down in the sidebar. And if I click to a different person and back to that person, their todos are fine. However, if not then the item doesn't go away - and if I click to the other person the first item is ticked for them too.

I'm not really sure how to diagnose this so would love a pointer. Thanks.

When you switch between selected persons, you're still rendering the same component tree. Any elements in the DOM that are shared with the previous selected person's render will be kept in place. Only the differences are applied as DOM transformations. So, as long as each list has some number of todos in it, and todos always render a checkbox input, there will be some checkbox inputs that get reused.

You can opt out of this by setting a unique key prop, which tells React to treat something as a unique instance of a component or element.

I would try updating the key here on the <Todo> to be a unique value for each person and todo combination:
Diff code:
person.todos.map((todo, i) => (
- <Todo key={i} i={i} todo={todo} onTaskChecked={onTaskChecked} />
+ <Todo key={`${person.id}-${todo}`} i={i} todo={todo} onTaskChecked={onTaskChecked} />
))

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.

Sad Panda posted:

It still doesn't immediately pop that item off my to-do list - I've coded it so when I check it, it pops it from the list.

It correctly sets the array to be a new version with the todo item removed, but doesn't re-render that version of the todo list. What's causing that? This also means that if I try to check multiple items off, it won't work. I assume that's because the rendered state in my todo list form is stale?

Even though you're updating the state in peopleData, you're not updating the state in selectedPerson, which has a copy of the old person object.

Instead of storing a copy of the entire person object in state, try storing a selectedPersonId, and then use a memo to derive the selected person from selectedPersonId and peopleData whenever either of them changes:
JavaScript code:
const [peopleData, setPeopleData] = useState(initialData);
const [selectedPersonId, setSelectedPersonId] = useState(undefined);
const selectedPerson = useMemo(() => {
  if (selectedPersonId === undefined) return undefined;
  return peopleData.find(({ id }) => id === selectedPersonId)
}, [peopleData, selectedPersonId]);

Adbot
ADBOT LOVES YOU

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
Alternative method: set a breakpoint in your JS code in a place where where that package is available. When the debugger hits the breakpoint and JS execution is paused, your console will have access to all variables in scope for the currently executing code.

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