Try   HackMD

Solidity Gas Optimization tip: Move frequently accessed storage variables into memory (stack)

Move frequently accessed storage variables into memory (stack)

If you are regularly accessing storage variables in a function, it can save gas by just creating a new memory variable (on the stack), as calling the SLOAD opcode multiple times is very expensive.

pragma solidity >=0.8.4;

contract Example {
  uint currentCounter; // << storage data variable

  // note: these examples have nothing to do with the use of require()
  // but simply due to how many times it loads from storage as opposed to memory.
  
  // 2786 gas
  function unoptimized() view public returns (uint) {
    require(currentCounter < 5); // load from storage
    require(currentCounter != 10); // again loads from storage

    return currentCounter; // again loads from storage
  }

  // 1177 gas
  function optimized() view public returns (uint) {
    uint _counter = currentCounter; // << load from storage, put it on stack once
    
    require(_counter < 5); // loads from the _counter on stack (cheap!)
    require(_counter != 10); // loads from the _counter on stack (cheap!)

    return _counter; // again loads from _counter
  }
 
}

Another example:

pragma solidity >=0.8.4;

contract Example {
  uint favNumber;

  // first run (setting to 5): 27310 gas
  // second run (setting again to 5): 27425 gas
  function unoptimized(uint newNum) public {
    require(newNum < 10);
    favNumber = newNum; 
  }

  // first run (setting to 5): 50310 gas
  // second run (setting again to 5): 23847 gas
  function optimized(uint newNum) public {
    uint _currentFavNum = favNumber;
    require(_currentFavNum < 10);
    if(_currentFavNum != newNum) {
      favNumber = newNum; 
    }
  }
}

This was originally posted on my guide to saving gas on Solidity where you can find 20+ other optimizations for saving gas in the EVM/solidity code.