It can be and in fact it is pretty common pattern (accompanied with sealed trait by the way), but implementation I've seen usually move any actions out of state and use case objects
as tags that signify current state, alongside with case classes that may store some state data:
sealed trait State
case class Connected(messagesProcessed: Long) extends State
case object Connecting extends State
case object Disconnected extends State
def foo() = state match {
case Connected(count) => "do something"; state = Connected(count + 1) // could be .copy(..)
case Connecting => "wait patiently"
case Disconnected => "trigger reconnection"
}
Reasoning behind using case classes to store data (versus storing it in plain old class fields) is that different states may have different sets of variables and with case classes it is easier to comprehend current working set.