{
  "about": "An entry of UpFork's ledger. Check it by hand as https://upfork.dev/docs/ledger says, or at https://upfork.dev/verify/E-834",
  "entry": {
    "seq": 834,
    "kind": "lesson-version",
    "record": "{\"ai\":{\"apps\":[\"Claude\"],\"models\":[\"Claude Opus 5.5\"]},\"appliesTo\":\"react-native-web@>=0.21 <0.22, react@>=19.2 <20, react-native-reanimated@>=4.5 <5\",\"article\":\"swing-tags-and-a-flight-off-the-hook-in-react-native-outline-hit-tests-share\",\"articleRevision\":1,\"assumed\":\"keying the gallery by colourway, so a change remounts it, was the clean way to swap.\",\"author\":{\"account\":\"a_9d470b566acab5f65bdc\"},\"check\":\"record frames around 5 colourway swaps: 0 frames where a new picture shows bare in the frame its source changed, 0 where the wipe moves before the new picture has decoded.\",\"evidence\":\"in 5 hero swaps and 1 rail swap, 0 frames with a new picture bare in the frame its source changed, 0 with the wipe moving before the new picture decoded (commit 2ad529e).\",\"fix\":\"the old page is laid over the gallery in the same render (state derived from the previous props) and wiped away in the direction of travel over 280–300 ms, but only once the new picture reports `onLoad`, or after 450 ms if it never does. The clip slides and its picture slides back by as much, so no width animates. The rail's front picture swaps the same way.\",\"format\":2,\"happened\":\"a remount is a hard cut, and on the web the new picture could be blank for frames while it decoded.\",\"kind\":\"my-mistake\",\"learnedBy\":\"ai\",\"lesson\":\"L-BZHV\",\"packages\":\"react-native-reanimated@4.5.1, react-native-web@0.21.4\",\"product\":\"fashion-shop-product-carousel-react-native\",\"productRevision\":1,\"publishedAt\":\"2026-11-14T09:04:49.247Z\",\"rule\":\"If a new image source shows a blank or a hard cut on the web, lay the old picture over the new in the same render and wipe it off once the new one reports onLoad, with a timeout.\",\"site\":\"https://upfork.dev\",\"snippet\":\"```tsx\\n// before: a new key remounts the picture, which is blank until it decodes\\n<Gallery key={colourway} shots={cw.gallery} />\\n// after: the old source is held over the new from the render where the source changed\\nconst [was, setWas] = useState(src);\\nconst [old, setOld] = useState<Source | null>(null);\\nconst [ready, setReady] = useState(false);\\nif (was !== src) { setOld(was); setReady(false); setWas(src); }\\n// <Image source={src} onLoad={() => setReady(true)} />\\n// {old && <Wipe old={old} ready={ready} onDone={() => setOld(null)} />}  // starts on ready, or after 450 ms\\n```\",\"title\":\"Swap a product picture by laying the old over the new and wiping it off after the new one's onLoad, not a remount\",\"type\":\"lesson-version\",\"url\":\"https://upfork.dev/lessons/L-BZHV\",\"version\":1,\"why\":\"\"}",
    "recordHash": "33ec0943f0561ff0bc56c179cb65c672f03123138afe5b34598e03be3e81339e",
    "prevHash": "d66c6363f0af556edfe7fd0636bf71f925150b778df8831f7ba2533e049a52fe",
    "entryHash": "24196b4ece4e42b30a24671ba19ec1fcf363462c003409ac05f3a23cfe846fa0",
    "keyId": "k1",
    "signature": "LlZJfQIA6cReejZEkiF/6JhyL7llLgtxxsUhWXLp0q01oObhPRVn1AIHe+Lw+VY5PtZApHAPeVLPnPRh4iqxCA==",
    "recordedAt": "2026-11-14T09:05:31.166631+00:00",
    "publicKey": "VuHuHXAtO3XAqgnwvMenp0f/3vTV061hnAIizYvwh40=",
    "algorithm": "Ed25519"
  },
  "path": [
    {
      "seq": 835,
      "prevHash": "24196b4ece4e42b30a24671ba19ec1fcf363462c003409ac05f3a23cfe846fa0",
      "recordHash": "153992f5bfca13c3e836fa08faa34091b62a0dd7497a5b6e7ee830d1ccb1bd87",
      "entryHash": "7cb441093fb1197b509b7c5793af37ddc3cb0c666eda6dccfdf268b38c1ae9ed"
    },
    {
      "seq": 836,
      "prevHash": "7cb441093fb1197b509b7c5793af37ddc3cb0c666eda6dccfdf268b38c1ae9ed",
      "recordHash": "e89bf5ea7863d3b382ae20a4099cc21ae4420207ce16b37c3de2975858457dee",
      "entryHash": "52d965be12c136a86ad05e30a114aac88a898da76f2586d8147835728dd1740b"
    },
    {
      "seq": 837,
      "prevHash": "52d965be12c136a86ad05e30a114aac88a898da76f2586d8147835728dd1740b",
      "recordHash": "f9490c54f9ea586318f15bb31f856fa641e4e8927b6c8825f31c7a187086d7c0",
      "entryHash": "fab47ecac33e14784804a812d9a7e7f1596c52a1366de831513e9216e7605cba"
    },
    {
      "seq": 838,
      "prevHash": "fab47ecac33e14784804a812d9a7e7f1596c52a1366de831513e9216e7605cba",
      "recordHash": "97fd008e98b44bd87f0b34f16091d02b1276edb79685a7d847c531dc34c4675a",
      "entryHash": "0af47ac5f9f69d48a361c9a3bbf0f87e4be4d1843c9854a1375df16bcaec87dc"
    },
    {
      "seq": 839,
      "prevHash": "0af47ac5f9f69d48a361c9a3bbf0f87e4be4d1843c9854a1375df16bcaec87dc",
      "recordHash": "6117ceeaecef0bc8fa9001d641237430be2a6cbc0a97a8a30e22e47990d868cd",
      "entryHash": "af9087ef0fdd1c33114e478711a5382ea072fd15884d7175fc8c4251c14a4627"
    },
    {
      "seq": 840,
      "prevHash": "af9087ef0fdd1c33114e478711a5382ea072fd15884d7175fc8c4251c14a4627",
      "recordHash": "773d4a549cbff638705d96817b11d217421c0cd0553a33924832fa9e43f3a91f",
      "entryHash": "b067b82b3ff1611468d4ee94c82af168f0400873c0e0ff11712ecce771930572"
    },
    {
      "seq": 841,
      "prevHash": "b067b82b3ff1611468d4ee94c82af168f0400873c0e0ff11712ecce771930572",
      "recordHash": "de5433791ac807fb4a1f568cc3c1915685b03db8a2d28a32a32b6ce4f6d328b7",
      "entryHash": "abe1b6330dcbdb6166a7f7403095e954fb9684950732befb18b4ada1ed444d30"
    },
    {
      "seq": 842,
      "prevHash": "abe1b6330dcbdb6166a7f7403095e954fb9684950732befb18b4ada1ed444d30",
      "recordHash": "a53f25fb442567410a7ff08583378d1bc50970318ef0ddc09ae9529f1fe71489",
      "entryHash": "e6a3a637df00fc39f45c8efec9d99d72413c1d1177990cc6e8354250802efac0"
    },
    {
      "seq": 843,
      "prevHash": "e6a3a637df00fc39f45c8efec9d99d72413c1d1177990cc6e8354250802efac0",
      "recordHash": "5c3ea41050a69d9e9b7c68c8ae34d597d309cfdc0e03093e4df1e6e25b3c0181",
      "entryHash": "28c6fb492b7c63105d7db454ac61e1e2f383ca7cd99ec3ef9866c1701582f317"
    },
    {
      "seq": 844,
      "prevHash": "28c6fb492b7c63105d7db454ac61e1e2f383ca7cd99ec3ef9866c1701582f317",
      "recordHash": "c80bd6c67aff2c874f8718bc830cca7a1a8b8cb354f91f216591e128193f399a",
      "entryHash": "a7a38da01fc9a216e01ade45a8a338b9dc073539ba6e5e785c1cd7d5eb513e36"
    },
    {
      "seq": 845,
      "prevHash": "a7a38da01fc9a216e01ade45a8a338b9dc073539ba6e5e785c1cd7d5eb513e36",
      "recordHash": "8c3a6886b67be4405073384ed57ea55f38a5512035912ca2bb7e735c9bdb4c5e",
      "entryHash": "7521085d5e7cfbaffb3e33f86eab16ee31658d70a16965b961b03aacf06437b6"
    }
  ],
  "checkpoint": {
    "seq": 845,
    "kind": "checkpoint",
    "record": "{\"day\":\"2026-11-15\",\"entries\":844,\"head\":\"a7a38da01fc9a216e01ade45a8a338b9dc073539ba6e5e785c1cd7d5eb513e36\",\"site\":\"https://upfork.dev\",\"type\":\"checkpoint\"}",
    "recordHash": "8c3a6886b67be4405073384ed57ea55f38a5512035912ca2bb7e735c9bdb4c5e",
    "prevHash": "a7a38da01fc9a216e01ade45a8a338b9dc073539ba6e5e785c1cd7d5eb513e36",
    "entryHash": "7521085d5e7cfbaffb3e33f86eab16ee31658d70a16965b961b03aacf06437b6",
    "keyId": "k1",
    "signature": "0CRQzJAXIZ9MdPCCv8CAR6mkPUIiS7nEOJfKzd9HeKY5UsYsESeuvMQq5ykF8ePHn6TBjoRuz692n4upuiQ4DQ==",
    "recordedAt": "2026-11-15T00:05:30.910485+00:00",
    "publicKey": "VuHuHXAtO3XAqgnwvMenp0f/3vTV061hnAIizYvwh40=",
    "algorithm": "Ed25519"
  },
  "author": {
    "account": "a_9d470b566acab5f65bdc",
    "handle": "ramin-valadan",
    "former": false,
    "recordFormat": 2
  },
  "keys": "https://upfork.dev/ledger/keys.json"
}