Skip to content

Commit 5646965

Browse files
committed
🐛: fix closure problem, [issue url](#2)
1 parent 06fc011 commit 5646965

File tree

2 files changed

+134
-1
lines changed

2 files changed

+134
-1
lines changed

app/src/main/java/xyz/junerver/composehooks/example/UseReducerExample.kt

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
package xyz.junerver.composehooks.example
22

33
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.foundation.layout.Row
45
import androidx.compose.foundation.layout.Spacer
56
import androidx.compose.foundation.layout.height
7+
import androidx.compose.foundation.layout.width
8+
import androidx.compose.material3.Button
9+
import androidx.compose.material3.Checkbox
10+
import androidx.compose.material3.MaterialTheme
611
import androidx.compose.material3.OutlinedTextField
712
import androidx.compose.material3.Surface
813
import androidx.compose.material3.Text
14+
import androidx.compose.material3.TextField
915
import androidx.compose.runtime.Composable
16+
import androidx.compose.runtime.getValue
17+
import androidx.compose.runtime.key
18+
import androidx.compose.runtime.mutableStateOf
19+
import androidx.compose.runtime.remember
20+
import androidx.compose.runtime.setValue
21+
import androidx.compose.ui.Alignment
1022
import androidx.compose.ui.Modifier
1123
import androidx.compose.ui.unit.dp
1224
import xyz.junerver.compose.hooks.Middleware
@@ -61,6 +73,7 @@ fun UseReducerExample() {
6173
TButton(text = "+1") {
6274
dispatch(SimpleAction.AgeIncrease)
6375
}
76+
TaskApp()
6477
}
6578
}
6679
}
@@ -74,3 +87,122 @@ fun <S, A> logMiddleware(): Middleware<S, A> {
7487
}
7588
}
7689
}
90+
91+
@Composable
92+
fun TaskList(tasks: List<Task>, onChangeTask: (Task) -> Unit, onDeleteTask: (Int) -> Unit) {
93+
tasks.forEach { task ->
94+
key(task.id) {
95+
TaskItem(task = task, onChange = onChangeTask, onDelete = onDeleteTask)
96+
}
97+
}
98+
}
99+
100+
@Composable
101+
fun TaskItem(task: Task, onChange: (Task) -> Unit, onDelete: (Int) -> Unit) {
102+
var isEditing by remember { mutableStateOf(false) }
103+
var text by remember { mutableStateOf(task.text) }
104+
105+
Row(verticalAlignment = Alignment.CenterVertically) {
106+
Checkbox(
107+
checked = task.done,
108+
onCheckedChange = { checked ->
109+
onChange(task.copy(done = checked))
110+
}
111+
)
112+
113+
if (isEditing) {
114+
TextField(
115+
modifier = Modifier.width(100.dp),
116+
value = text,
117+
onValueChange = { newText ->
118+
text = newText
119+
onChange(task.copy(text = newText))
120+
}
121+
)
122+
Button(onClick = { isEditing = false }) {
123+
Text("Save")
124+
}
125+
} else {
126+
Text(text = task.text)
127+
Button(onClick = { isEditing = true }) {
128+
Text("Edit")
129+
}
130+
}
131+
132+
Button(onClick = { onDelete(task.id) }) {
133+
Text("Delete")
134+
}
135+
}
136+
}
137+
138+
data class Task(val id: Int, val text: String, val done: Boolean)
139+
140+
@Composable
141+
fun AddTask(onAddTask: (String) -> Unit) {
142+
var text by remember { mutableStateOf("") }
143+
144+
Row {
145+
TextField(
146+
modifier = Modifier.width(100.dp),
147+
value = text,
148+
onValueChange = { newText ->
149+
text = newText
150+
},
151+
placeholder = { Text("Add task") }
152+
)
153+
Button(onClick = {
154+
onAddTask(text)
155+
text = ""
156+
}) {
157+
Text("Add")
158+
}
159+
}
160+
}
161+
162+
@Composable
163+
fun TaskApp() {
164+
val (tasks, dispatch) = useReducer<List<Task>, TaskAction>(
165+
{ prevState, action ->
166+
when (action) {
167+
is TaskAction.Added -> prevState + Task(nextId++, action.text, false)
168+
is TaskAction.Changed -> prevState.map { if (it.id == action.task.id) action.task else it }
169+
is TaskAction.Deleted -> prevState.filter { it.id != action.taskId }
170+
}
171+
},
172+
initialTasks,
173+
arrayOf(
174+
logMiddleware()
175+
)
176+
)
177+
178+
fun handleAddTask(text: String) {
179+
dispatch(TaskAction.Added(text))
180+
}
181+
182+
fun handleChangeTask(task: Task) {
183+
dispatch(TaskAction.Changed(task))
184+
}
185+
186+
fun handleDeleteTask(taskId: Int) {
187+
dispatch(TaskAction.Deleted(taskId))
188+
}
189+
190+
Column {
191+
Text(text = "Day off in Kyoto", style = MaterialTheme.typography.titleLarge)
192+
AddTask(onAddTask = ::handleAddTask)
193+
TaskList(tasks = tasks, onChangeTask = ::handleChangeTask, onDeleteTask = ::handleDeleteTask)
194+
}
195+
}
196+
197+
var nextId = 3
198+
val initialTasks = listOf(
199+
Task(id = 0, text = "Philosopher’s Path", done = true),
200+
Task(id = 1, text = "Visit the temple", done = false),
201+
Task(id = 2, text = "Drink matcha", done = false)
202+
)
203+
204+
sealed interface TaskAction {
205+
data class Added(val text: String) : TaskAction
206+
data class Changed(val task: Task) : TaskAction
207+
data class Deleted(val taskId: Int) : TaskAction
208+
}

hooks/src/main/kotlin/xyz/junerver/compose/hooks/useReducer.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ fun <S, A> useReducer(
2828
middlewares: Array<Middleware<S, A>> = emptyArray(),
2929
): Tuple2<S, Dispatch<A>> {
3030
val (state, setState) = _useState(initialState)
31-
val dispatch = { action: A -> setState(reducer(state, action)) }
31+
val stateRef = useLatestRef(value = state)
32+
val dispatch = { action: A -> setState(reducer(stateRef.current, action)) }
3233

3334
val enhancedDispatch: Dispatch<A> = { action ->
3435
var nextDispatch: Dispatch<A> = dispatch

0 commit comments

Comments
 (0)