Year #2, Week #12 💻 🛸

New stuff we learned this week: 🤔

CSS: Object-Fit and Object-Position

  • when applying an image as a css background image, we’ve learned that we can control the fit, sizing, and placement of the background image within the containing element:
.my-div-with-img-background {
  background-image: url(./cats.jpg);
  background-size: cover; /* <-- 👋 */
  background-position: center; /* <-- 👋 */
}
  • we can achieve the same sort of control over regular <img /> tags as well, by controlling the dimensions of the image element and describing how we want to fit the image within those dimensions using object-fit and object-position:
<style>
  img {
    width: 200px;
    height: 200px;
    object-fit: cover; /* <-- 👋 */
    object-position: center; /* <-- 👋 */
  }
</style>

<img src="./cats.jpg" />
  • values for object-fit include:
    • contain (like background-size: contain)
    • cover (like background-size: cover)
    • fill (stretch/force image to match dimensions)
    • none (do nothing, act like a normal image)
  • object-position can be set like so:
    • object-position: 50% 50%; (this is the default)
    • object-position: right top;
    • object-position: left bottom;
    • object-position: 100px 30px;
  • For more info, and interactive demos, see MDN for object-fit and object-position

HTML: image srcSet

  • When it comes to HTML images, we have a thorny problem. Some users of our websites will be viewing from a very small screen, like a phone. While others have massive ultra-high-definition 6k monitors. How big should we make our images then? If we make them beautiful for large monitors, they will load slowly and not look any better for people on phones. If we optimize for phones, they images will load fast for everyone, but look terrible on big screens. What to do!??
  • the browser makers have helped us out by extending the HTML spec so that <img /> tags now supports some new attributes, one of which is srcset:
<img
  srcset="cats-small.jpg 480w, cats-full.jpg 800w"
  src="cats-full.jpg"
  alt="My rad cat"
/>
  • the srcset attribute lets us specify more than one image, with information about their actual size. Then, the browser will pick the right source to load based on the width of the screen of the user viewing the page.
  • because we sometimes do tricky things and display images at different sizes based on media queries, there’s also another attribute called sizes which allows us to explicitly tell the browser what image to use at which screen sizes:
<img
  srcset="cats-small.jpg 480w, cats-full.jpg 800w"
  sizes="(max-width: 600px) 480px, 800px"
  src="cats-full.jpg"
  alt="My rad cat"
/>

Javascript: Equality and non-primitive types

  • In javascript, primitive values are tested for equality by value:
let x = 3;
let y = 3;

x === y;
// -> true

let str1 = "foo";
let str2 = "foo";

str1 === str2;
// -> true
  • However, non-primitives are tested for equality (when using triple-equals) by reference — which basically means “is it actually the same THING in memory”:
let arr1 = [0];
let arr2 = [0];

arr1 === arr2;
// -> false 🧐

let obj1 = {};
let obj2 = {};

obj1 === obj2;
// -> false 🧐
  • sort of the flip-side of this is that you can have two variables that REFERENCE THE SAME data structure (like an array or object), and if you mutate one of them, you’re mutating the other at the same time because they are just two variables pointing to the same piece of memory. Consider this snippet of code:
let kids = [`Win`, `Harriet`];

// 🚨 careful! `students` is not a NEW array
// its just another name for the `kids` array
let students = kids;

// 😎 this is `true` because they are THE SAME ARRAY
students === kids;
// -> true

// now we mutate the `students` array
students.push(`Tabitha`);

// the `kids` array got mutated too
console.log(kids);
// -> ['Win', 'Harriet', 'Tabitha'`]

Non-primitive state in React

  • Before React calls your render function to re-reconcile the virtual DOM against the real DOM, if first checks if any of the props have changed using ===. If no props have changed, it skips re-rendering, for speed’s sake.
  • This works as expected for primitive values in state, like numbers, booleans, strings, etc. But if you have a piece of state that is an array or object, and you only mutate the state, React won’t see that anything has changed, and won’t re-render, causing a weird bug:
const App: React.FC => () => {
  const [pets, setPets] = useState([`Fern`, `Scout`]);
  return (
    <div onClick={() => {
      // 🚨 BAD! `<Pets />` component below won't re-render
      // because the `pets` array isn't a NEW array
      pets.push(`Dumpy`);
      setPets(pets);
    }}>
      <Pets pets={pets} />
    </div>
  );
}
  • The way to work around this limitation is to use array or object SPREADING to create a new object or array:
const App: React.FC => () => {
  const [pets, setPets] = useState([`Fern`, `Scout`]);
  return (
    <div onClick={() => {
      // ✅ WORKS! spreading creates a NEW array
      // so react will notice the change and re-render
      setPets([ ...pets, `Dumpy` ]);
    }}>
      <Pets pets={pets} />
    </div>
  );
}

Useful Links:


Homework Plan (2 weeks)



  • Akron Snowmen Assignment


    • connect with vscode into your akron-snowmen dir
    • switch your branch to master and pull from upstream
    • delete any branches you have hanging around (practice good git hygiene!)
    • run npm install to make sure you have the husky pre-commit hook stuff working from here on out.
    • create a new branch for this weeks’ work.
    • find your name below and complete the assigned work
    • when you finish, submit a MR
    • for each other student, leave at least one detailed comment requesting a change in the code.
    • incorporate at least one of the other student’s suggestions on your MR.
    • Important: - once again this week, we’re only working in Storybook. Starting the next week, we’ll begin putting things together in Next, but not this week. You should only be using npm run storybook and npm run build-storybook
    • when you’re finished, submit a MR, build the Storybook site, and submit both URLs on slack.

    Akron Snowman Sub-Assignments


    • Tabitha:
      • change the Image component so that it uses next/image <Image /> component, instead of a background image.
      • use objectFit and objectPosition props to get it looking right
      • refer to this documentation if necessary
      • images are in the public/ dir, and should be referenced like this /plow.jpg, without the public/ dir in the path, that’s how Next works.
      • also, win’s comonent is really the whole block that contains an image and the text, so Image isn’t the best name for it, rename the component and the files.
      • make sure that the storybook stories still work
    • Win:
      • Make a ContactBlock component, matching the purple block on the example site.
      • Much of the content will be just you pulling in and using Tabitha’s Form component, but you’ll need to create the rest of the block, and make sure everything has the correct layout and media queries, etc.
      • remember mobile-first
      • create a storybook story fot it
    • Harriet:
      • create a PinkBlock component to house Kiah’s PingGrid comopnent, making it match the example site
      • use the Button component
      • create a storybook story for it
    • Willow:
      • create a Footer component, to match the one on the example site.
      • start with mobile first
      • create a storybook story for it
    • Kiah:
      • create a HeroBlock component for the main big first (non-nav) block on the example site
      • use next/image and css positioning wizardry to make the snow plow image be behind the text, don’t use css background images for this one (at least for now)
      • mobile first
      • create a storybook story for it
      • incorporate the Button component in it.

    Tic Tac Toe Challenge 💪


    • go to this url, fork, then clone to vscode
    • run npm install to get dependencies
    • create a new branch
    • create a working tic-tac-toe game ✅
    • hints/helps:
      • fire up the dev server with npm start and start working
      • take baby steps, and commit often
      • maybe start by just visually making a tic-tac-toe board, with a signal of whose turn it is (X or O), and if someone has won the game.
      • take a few minutes to think carefully about what pieces of state you will need
      • it’s probably wise to extract a <Square /> component for each of the nine squares
      • I put an empty jest test script in the src/__tests__ dir for you, so if you have something complicated you want to write a function for, consider writing tests, and doing test-first development (making a failing test, then getting it to pass)
      • remember keep the MINIMUM state possibledon’t track with state what you can DERIVE FROM STATE.
      • you might end up wanting a piece of non-primitive state to hold the state of the squares — if you do, remember to spread.
    ← All homework