Skip to content
pablichjenkov edited this page Jan 23, 2023 · 31 revisions

What is UiState3

When you write code in compose, very often, you bind a State to a Composable function in the following manner.

val composeRootState = ComposeStateRootFactory.getState() // This state is host somewhere in your Application

setContent {
    ComposeRootRendererFunction(composeRootState) // This function is isolated from the State it renders
}

Very often too, your App state will be composed of other sub state classes within itself. We can model it like bellow, let's assume we have a nested renderable state with 3 levels.

class ComposeStateRootImpl: IComposeStateRoot {
    val composeStateLevel2 = ComposeStateLevel2()
}

class ComposeStateLevel2Impl : IComposeStateLevel2 {
    val composeStateLevel3 = ComposeStateLevel3()
}

class ComposeStateLevel3Impl : IComposeStateLevel3

Typically to render that App state we will do something like:

@Composable
fun ComposeRootRendererFunction(stateRoot: IComposeStateRoot) {
    ...
    ComposeLevel2RendererFunction(stateRoot.composeStateLevel2)
    ...
}

@Composable
fun ComposeLevel2RendererFunction(stateLevel2: ComposedStateLevel2) {
    ...
    ComposeLevel3RendererFunction(stateLevel2.composeStateLevel3)
    ...
}

@Composable
fun ComposeLevel3RendererFunction(stateLevel3: ComposedStateLevel3) {
    // do something with stateLevel3
}

The binding of a composable and the state it renders inside a composable is pretty straightforward. However, the root state doesn't have a parent state. It lives somewhere else, usually the platform entry point component. In Android for instance, you would use it like bellow:

class MainActivity : ComponentActivity() {

    // MainActivity host the state
    val composeStateRoot = ComposeStateRootProvider.get()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // MainActivity hooks the state in to the Composable renderer function
        setContent {
            ComposeRootRendererFunction(composedStateRoot)
        }
    }
}

In this case, the Activity plays the role of the glue class that binds the 2 elements, the function and the state it renders. The same role the Activity is playing in this example, is the same role a Node does in UiState3. A node is basically a class that host a state for a composable function to render at some point.

class SomeNode : Node {
    val context: NodeContext = NodeContext()
    
    val someNodeState: SomeNodeState()
    
    //...

    @Composable
    abstract fun Content(modifier: Modifier) {
        SomeNodeComposable(someNodeState)
    }

    //...
}

@Composable
fun SomeNodeComposable(someNodeState: SomeNodeState) {}

data class SomeNodeState

That is all it is, a glue class for 2 things, a Composable function and the State it renders.
Now, the major difference between the Activity and a Node, is that you have control of its constructor and internal implementation, things you don't have in the Android Activity per say, and it really makes a huge difference. This allows you to build Node trees or any other structure, control of dependency injection, control of Node serialization, control of your own back stack and so much.
Continue exploring the project and you will find out.

Getting Started

Clone this wiki locally