Thinking about it, I found an alternative solution for this problem. The idea is create two vars in UIComponentBase:
private transient Boolean _cachedIsRendered;
private transient Renderer _cachedRenderer;
copy the code from UIComponent.encodeAll() to UIComponentBase. Then, do the same trick for cache FacesContext, but on encodeAll(). The idea is set _cachedRendered and _cachedIsRendered at the beginning and then clear this variables before end the method.
Then, some code is added in isRendered() and getRenderer() to check for the cached var and if is set, return that value. In this way we have control about the cached var. If by some reason encodeXXX() is called instead encodeAll(), the code will work as expected. The same thing can be done in decode() method, but in this case only for _cachedRendered, preventing a second call when getClientId() is called.
In this way we can save between 6 and 8 lookups to a map. isRendered() is called only once per component, which is valid because this value does not change while encoding of the same component occur. Also, it preserves getRenderer() plugability, because it is possible to change the renderKit before render response time and reflect the change.