Is this extra case (and the whole `fullyloaded` attribute) really needed? If it doesn't cost much, efficiency-wise, I think it would be cleaner if the object didn't have to make decisions based on it being "fully loaded". Calling `load()` would just cache all existing reactions, and could even cache some important non-existing reactions as `None`, if that's a performance problem. Then, this method could just look all existing reactions up quickly, and let the specific DataSource implementation handle the rest.
This is just an opinion. There is (afaik) nothing wrong with your implementation.