简体   繁体   中英

Jetpack Compose will not recompose if function is called directly from textbutton onClick()

I have a function that should clear an List ( guessArray ) removing all the text from the view. If this function is called from anywhere including composables it seems to work, except for when it is called from the onClick of an AlertDialog.

updated vars:

var guessArray = List(5) { List(6) { CardData("", Color.White) }.toMutableStateList() }
private var column = 0
private var greenLetterList = mutableListOf<String>()
private var yellowLetterList = mutableListOf<String>()
private var grayLetterList = mutableListOf<String>()

function:

fun newGame() {
    greenLetterList.clear()
    grayLetterList.clear()
    yellowLetterList.clear()
    guessArray = List(5) { List(6) { CardData("", Color.White) }.toMutableStateList() }
    currentRow = 0
    column = 0
}

AlertDialog:

@Composable
fun GameEndPopUp(viewModel: HomeViewModel) {
    val openDialog = remember { mutableStateOf(viewModel.gameIsInPlay) }
    if (!openDialog.value.value) {
        AlertDialog(
            onDismissRequest = { openDialog.value.value = true },
            confirmButton = {
                TextButton(
                    onClick = {
                        openDialog.value.value = true
//this doesnt work
                        viewModel.newGame()
                    },
                    modifier = Modifier
                        .width(53.dp)
                        .height(50.dp),
                )
                { Text(text = "Next Word") }
            }
        )
    }
}

Could it be that specifically AlertDialogs are the problem here? Calling from this onClick works perfectly:

@Composable
fun MyEnterButton(viewModel: HomeViewModel) {
    val coroutineScope = rememberCoroutineScope()
    val mContext = LocalContext.current

    Button(
        onClick = {
            if (viewModel.gameIsInPlay.value) {
                coroutineScope.launch {
                    if (viewModel.checkWordExists()) {
                        viewModel.checkLetterPlacementIsCorrect()
                        viewModel.checkKeyboard()
       //this works
                        viewModel.newGame()
                    } else {
                        viewModel.toastWordNotFound(mContext)
                    }
                }
            }
        }
    )
}

Your current code sets the variable guessArray to a new mutable state. This will not trigger recomposition because the state your composable observes does not change.

guessArray = List(5) { List(6) { CardData("", Color.White) }.toMutableStateList() }

I would write this code quite differently, but the minimal change that might work for you is changing the line in newGame() to:

guessArray.value = List(5) { List(6) { CardData("", Color.White) } }

Then you will be updating the mutable state of guessArray , which should trigger recomposition. You should also change guessArray from var to val .

Edit: This is more like how I would do it:

@Composable
fun HomeScreen(viewModel: HomeViewModel) {
    /* 
        Rest of the home screen UI here
    */

    if (viewModel.state.value.showGameEndPopUp) {
        AlertDialog(
            onDismissRequest = { viewModel.onDismissGameEndPopUp() },
            confirmButton = {
                TextButton(
                    onClick = {
                        viewModel.onNextWordClick()
                    },
                    modifier = Modifier
                        .width(53.dp)
                        .height(50.dp),
                )
                { Text(text = "Next Word") }
            }
        )
    }
}

class HomeViewModel : ViewModel() {

    private val _state = mutableStateOf(HomeUiModel())
    val state: State<HomeUiModel> = _state

    data class HomeUiModel(
        val column: Int = 0,
        val showGameEndPopUp: Boolean = false,
        val greenLetterList: List<String> = emptyList(),
        val yellowLetterList: List<String> = emptyList(),
        val grayLetterList: List<String> = emptyList(),
        val guessArray: List<List<CardData>> = List(5) { List(6) { CardData("", Color.White) }}
    )

    fun onDismissGameEndPopUp() {
        _state.value = _state.value.copy(showGameEndPopUp = false)
    }

    fun onNextWordClick() {
        // Start a new game
        _state.value = HomeUiModel()
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM