there are three front-end framework concepts that are easily confused:
-
responsive updates
-
unidirectional data flow
-
Bidirectional data binding
before continuing with this article, readers can think about whether they clearly know the meaning of the three.
these three are easy to be confused because although they belong to the same front-end framework, they are not the same level of abstraction, so it is difficult to compare them directly.
this article will explain the differences between these three levels of abstraction.
responsive updates
responsive update is also called fine-grained update . At the same time, the recently popular concept of Signal
describes responsive updates .
In a nutshell, responsive update describes the relationship between state and UI , that is, how state changes map to UI changes .
consider the following example (from what are signals article):
function TodoApp() {
const [todos, setTodos] = useState(
[{ text: 'sleep', completed: false }]
)
const [showCompleted, setShowCompleted] = useState(false)
const filteredTodos = useMemo(() => {
return todos.filter((todo) => !todo.completed || showCompleted)
}, [todos, showCompleted])
return (
<TodoList todos={filteredTodos} />
)
}
in the TodoApp
component, two states are defined:
-
to-do
todos
-
whether to show completed items
showCompleted
and the state derived from the above state filteredTodos
. Finally, the & lt;TodoList/>
component is returned.
if the state of todos
changes, how does UI
change? That is, how do we know the scope of influence of state changes ? At this point, there are two ideas:
-
push (
push
) -
pull (
pull
)
the principle of push
We can start with the changing state ( todos
in the example) and push it all the way according to the derivative relationship of the state.
Pictures are from what are signals
in the example:
-
todos
change -
filteredTodos
is derived fromtodos
, and the change is transmitted to him -
& lt;TodoList/>
component depends onfilteredTodos
, and the change is transmitted to him -
after determining the final influence range of
todos
change, update the correspondingUI
this establishes the relationship between the state and UI .
in addition to pushing , there is another way called pulling .
the principle of pulling
For the same example of
, we can also establish the relationship between the state and possible UI changes , and then deduce the range of UI
changes.
Pictures are from what are signals
in the example:
-
todos
change -
there may be
UI
changes (because the relationship between the state and possible UI changes is established ) -
UI
is related to the& lt;TodoList/>
component to determine whether it has changed. -
& lt;TodoList/>
components depend onfilteredTodos
,filteredTodos
is derived fromtodos
, sofilteredTodos
is a changing. -
now that
filteredTodos
has changed,& lt;TodoList/>
components may change -
calculate the range of influence of the change, update
UI
in mainstream frameworks, React
is updated mainly by pushing , while Vue
, Preact
, Solid.js
and other frameworks use pull .
the responsive update discussed in this article is an implementation of pulling .
unidirectional data flow
We can find that whether pushes or pulls , they all need to calculate the range of influence of the change, that is, how many components will be affected after a state change .
then, from the perspective of the framework author, you want to add some constraints to reduce the complexity of the process of calculating the scope of influence .
Similarly, from the perspective of framework users, you also want to add some constraints to make it easier to troubleshoot problems when calculates the scope of influence bug
.
this gives you one-way data flow .
one-way data flow is a convention that specifies when the state changes, the impact of the change is passed only from top to bottom .
consider the following example:
function Parent() {
const [num] = useState(0);
return <Child data={num}/>;
}
function Child({data}) {
const isEven = data % 2 === 0;
return <GrandChild data={isEven}/>;
}
function GrandChild({data}) {
return <p>{data}</p>;
}
& lt;Parent/>
component num
as props
to & lt;Child/>
component, and as props
to & lt;GrandChild/>
component, the whole process can only be from top to bottom.
one-way data flow is not a principle that must be followed in the implementation of a front-end framework. Its existence is mainly to reduce the mental burden of developers and make the process of calculating the scope of influence more controllable after the state of changes.
Bidirectional data binding
when this article begins with responsive updates , it discusses the relationship between state and UI , which discusses the framework as a whole with a high level of abstraction.
when we continue to talk about one-way data flow , we are talking about the scope of influence of state changes spreading unidirectionally between components, which is the relationship between components and components , and the level of abstraction goes down one level.
the next bidirectional data binding is about what happens within a single component.
Bidirectional data binding is the syntax sugar of state + callback triggered after state change .
it is not discussed here whether the word "grammatical sugar" is completely accurate in the frame context
the well-known bi-directional data binding implementation, such as v-model
syntax:
in Vue
<input v-model=‘data’/>
is equivalent to the following combination of status and event callback:
<input @input='onInput' :value=‘data’ />
in fact, there is a similar implementation in
React
in the early days, called LinkedStateMixin , but has long been abandoned.
Summary
to sum up, there are two main points:
-
they are all concepts within the front-end framework
-
they belong to concepts of different levels of abstraction
where:
-
Bidirectional data binding describes the relationship between logic and views within components
-
unidirectional data flow describes the relationship between components
-
responsive update describes the relationship between status and UI