What you say is mostly true.
Your code still tokenizes every line for every drawing when it need not do so. It also relies on newlines embedded in the text.
Another way is to tokenize once (using newlines in the file, or a width, or whatever) and store those as character indices, not newline characters. Then, when drawing, you need not recompute the indices, but merely draw the substrings from one index to the next as separate lines.
This is not really more complicated than what you have. And that approach lends itself well to resizing, because you need not alter your text, just the indices of where new lines are.
The function I wrote above will not scroll, and it isn't efficient because it also does computation for every draw that it need only do once. But it's sufficient for drawing text into a rectangle without manually predetermining where all the newlines should be. That's ideal during development, even if for release you change it to a static layout by figuring out where to place new lines.
The nice thing about these forums is that readers have so many different solutions to choose from. It never hurts to see different approaches. Also, they are commented so they make a good starting point even if you want to alter them into something different.