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.