Closed lukaspili closed 3 years ago
Hello!
Why do you want to force a rerender? What's the purpose?
I want the textfield to always reflect the value from the state notifier provider, except when it's in focus and user is typing inside (in order to avoid re-renders). The purpose is to be able to change/reformat the entered input once editing is finished and have the textfield to show the updated value.
The request for re-render is to handle the edge case:
foobar123
onChange('foobar123')
=> update state with 'foobar'
(let's say we don't want any numbers and inputformatters don't exist, so we manually strip digits in the update method from state notifier)foobar
foobar456
onChange('foobar456')
=> update state with 'foobar'
(stripping numbers again)'foobar' == 'foobar'
(new value from step 5). And textfield still shows the raw input from the user foobar456
Thus, forcing re-render at step 5 would avoid the bug described at step 6.
But maybe it's the wrong way to looking at the problem. I don't like having the view state (driven by state notifier provider) to not always be in sync with the view.
The reason it's not in sync is to avoid rebuilding the textfield every time a character is typed. And only update the state value once editing has finished (textfield lost the focus).
From my past experiences with this kind of architecture (view state = single source of truth and unidirectional data flows), it's useful to be able to update the state without triggering a render. For instance, exposing a silent
param on context.read
:
ListenableTextField(
value: _stateProvider.state.select((s) => s.someValue),
onChanged: context.read(_stateProvider, silent: true).updateSomeValue, // this time onChanged is called every time a new char is typed,
);
Calling state notifier mutation methods when silent == true
would not trigger re-render, even if state has changed. Which makes sense because we update the state as a reaction from a view change, in order to keep the state in sync.
Again, I'm not familiar at all with riverpod, so I'm not sure if any of it makes sense. What do you think?
You probably should drive your textfield by a "value" then.
Forcing rerenders is very hacky. You should probably refractor your code such that the UI and the state aren't out of sync
This is the case: ListenableTextField
is driven by _stateProvider.state.select((s) => s.someValue)
and gets rebuild whenever someValue
changes (it's a HookWidget and it's using useProvider()
But I would also like to avoid rebuilding the textfield when someValue
is updated from a keyboard input event, while still updating the value in the state notifier.
Why make the widget rebuild when the state changes then?
Because I still want to be able to rebuild the widget when I change the state from some other action. For instance, refresh some API and update/override the field with a new value. Or the example explained above -> modify the value after user finished typing.
For instance, refresh some API and update/override the field with a new value.
But why does the TextField needs to rebuild for this? The textfield isn't the one triggering the requests, right?
modify the value after user finished typing.
That can be done on other textfields life-cycles, like on unfocus/submit, with TextEditingController and/or FocusNode Why use a declarative API here?
Closing as the issue appears to be stale.
Just started experimenting with riverpod + statenotifer + freezed so I'm not sure where the question belongs. I'm looking to manually re-render a
ConsumerWidget
even if its watched value hasn't changed.I have a widget with a textfield driven by a viewstate, generated by freezed and contained in a statenotifier:
The following example shows the issue and what I want to achieve:
doubleValue
is null12.
in the textfield (not catched by inputformatter) and finishes editingonChanged
->updateDoubleValue
-> new state withdoubleValue = 12
12
(textfield value changed from12.
to12
)12.
again and finishes editingonChanged
->updateDoubleValue
-> new state withdoubleValue = 12
The reason is that at step 6, the new state is the same as the previous one, so
_stateProvider.state.select((s) => s.doubleValue?.toString() ?? '')
doesn't trigger a new render. While the textfield still shows12.
.Is there a way to force a re-render for this kind of scenario?
It could also be solved by changing
doubleValue
to string and continuously updating it while user writes in the field. Like this when editing ends, the format would change the state value if necessary and always trigger a render. However that's not great because it implies the textfield will be re-rendered at every char type.