概述
react发送和接收请求
by Luca Matteis
卢卡·马蒂斯(Luca Matteis)
React行为编程简介:请求,等待和阻止 (An intro to Behavioral Programming with React: request, wait, and block)
Behavioral Programming (BP) is a paradigm coined in the 2012 article by David Harel, Assaf Marron, and Gera Weiss.
行为编程(BP)是David Harel,Assaf Marron和Gera Weiss在2012年的文章中提出的范式。
Directly from the abstract:
直接摘自:
Behavioral programming simplifies the task of dealing with underspecification and conflicting requirements by enabling the addition of software modules that can not only add to but also modify existing behaviors.
行为编程通过启用添加不仅可以添加而且可以修改现有行为的软件模块,简化了处理规格不足和冲突需求的任务。
高级概念 (High-level concepts)
I’ll first explain the high-level concepts using an example of two React components MoviesList
and MoviesCount
. One displays a list of movies, the other a number of how many movies there are. Then I will dive into how exactly behavioral programming works.
我将首先使用两个React组件MoviesList
和MoviesCount
的示例来解释高级概念。 一个显示电影列表,另一个显示电影数量。 然后,我将深入探讨行为编程的工作原理。
Both components fetch data from the same HTTP URL. They were developed by two different teams in a large organization. When we render both components on a page, we have a problem as they perform the same request:
这两个组件都从相同的HTTP URL获取数据。 它们是由大型组织中的两个不同团队开发的。 当我们将两个组件都呈现在页面上时,我们会遇到一个问题,因为它们执行相同的请求:
<> <MoviesList /> <MoviesCount /></>
Little did we know that these are behavioral components. This means that we can do something quite clever to avoid both requests firing:
我们几乎不知道这些是行为成分 。 这意味着我们可以做一些非常聪明的事情来避免两个请求都被触发:
const MoviesCountFromList = withBehavior([ function* () { // block FETCH_COUNT from happening yield { block: ['FETCH_COUNT'] } }, function* () { // wait for FETCH_LIST, requested by the other // MoviesList component, and derive the count const response = yield { wait: ['FETCH_LIST'] } this.setState({ count: response.length }) }])(MoviesCount)
In the above example, we stepped inside the MoviesCount
component. We waited and requested for something to happen. And, more uniquely to behavioral programming, we also blocked something from happening.
在上面的示例中,我们进入了MoviesCount
组件。 我们等待并要求发生一些事情。 而且,对于行为编程而言,更独特的是,我们还阻止了某些事情的发生。
Because we were trying to avoid both requests from firing, we blocked the FETCH_COUNT
event from being triggered (since the same data was already acquired by the FETCH_LIST
event).
因为我们试图避免触发两个请求,所以我们阻止了FETCH_COUNT
事件的触发(因为FETCH_LIST
事件已经获取了相同的数据)。
<> <MoviesList /> <MoviesCountFromList /></>
Adding functionality to existing components without modifying their code is the novelty of the behavioral programming paradigm.
在不修改其代码的情况下向现有组件添加功能是行为编程范例的新颖之处。
Intuitively, this can allow the creation of more reusable components.
直观地讲,这可以允许创建更多可重用的组件。
In the rest of the article, I’ll go more in depth into how behavioral programing (BP) works, specifically in the context of React.
在本文的其余部分,我将更深入地研究行为编程(BP)的工作方式,特别是在React的上下文中。
重新思考编程流程 (Rethinking programming flow)
To achieve the above functionality, we need to think about programming behaviors a bit differently. Specifically, events play a crucial role in orchestrating the synchronization between the various behaviors we define for our components.
为了实现上述功能,我们需要对编程行为有所考虑。 具体而言, 事件在协调我们为组件定义的各种行为之间的同步中起着至关重要的作用。
const addHotThreeTimes = behavior( function* () { yield { request: ['ADD_HOT'] } yield { request: ['ADD_HOT'] } yield { request: ['ADD_HOT'] } })
const addColdThreeTimes = behavior( function* () { yield { request: ['ADD_COLD'] } yield { request: ['ADD_COLD'] } yield { request: ['ADD_COLD'] } })
run( addHotThreeTimes, addColdThreeTimes)
When we run the above code, we get back a list of requested events:
当我们运行上面的代码时,我们返回一个请求事件的列表:
ADD_HOTADD_HOTADD_HOTADD_COLDADD_COLDADD_COLD
As expected, the first behavior executes. Once it’s done, the second behavior continues. However, new specifications for our component require us to change the order in which both events are triggered. Rather than triggering ADD_HOT
three times, and then ADD_COLD
three times, we want them to interleave and trigger ADD_COLD
right after a ADD_HOT
. This will keep the temperature somewhat stable.
如预期的那样,将执行第一个行为。 完成后,第二个行为继续。 但是,针对组件的新规范要求我们更改触发两个事件的顺序。 而不是触发ADD_HOT
三次,然后ADD_COLD
三次,我们希望他们交织和触发ADD_COLD
一个之后ADD_HOT
。 这样可以使温度保持稳定。
...
const interleave = behavior( function* () { while (true) { // wait for ADD_HOT while blocking ADD_COLD yield { wait: ['ADD_HOT'], block: ['ADD_COLD'] }
// wait for ADD_COLD while blocking ADD_HOT yield { wait: ['ADD_COLD'], block: ['ADD_HOT'] } } })
run( addHotThreeTimes, addColdThreeTimes, interleave)
In the above example, we introduce a new interleave behavior which does exactly what we need.
在上面的示例中,我们引入了一种新的交错行为,该行为正是我们需要的。
ADD_HOTADD_COLDADD_HOTADD_COLDADD_HOTADD_COLD
We changed the order of when things get executed, without having to modify the code of already-written behaviors.
我们更改了事情执行的顺序 ,而不必修改已经编写的行为的代码。
The process is summarized in the graphic below.
下图总结了该过程。
The key concepts of this way of programming are the request, wait, and block operators. The semantics for these operators are:
这种编程方式的关键概念是request , wait和block运算符。 这些运算符的语义是:
Requesting an event: proposing that the event be considered for triggering, and asking to be notified when it is triggered
请求事件:建议考虑将事件触发,并要求在事件触发时得到通知
Waiting for an event: without proposing its triggering, asking to be notified when the event is triggered
等待事件:不建议触发事件,而是要求在事件触发时得到通知
Blocking an event: forbidding the triggering of the event, vetoing requests of other b-threads.
阻止事件:禁止事件触发,否决其他b线程的请求。
Each b-thread (behavioral thread) lives on its own and is unaware of other threads. But they’re all interwoven at runtime, which allows them to interact with each-other in a very novel way.
每个b线程(行为线程)独立存在,并且不知道其他线程。 但是它们都是在运行时交织在一起的,这使它们可以以一种非常新颖的方式彼此交互。
The generator syntax is essential to the functioning of a behavioral program. We need to control when to proceed to the next yield statement.
生成器语法对于行为程序的运行至关重要。 我们需要控制何时进行下一个yield语句。
回到React (Back to React)
How can these BP concepts be used in the context of React?
这些BP概念如何在React的上下文中使用?
Turns out that through high-order components (HOCs), you can add this behavioral idiom to existing components in a very intuitive fashion:
事实证明,通过高阶组件(HOC),您可以以非常直观的方式将此行为习惯用法添加到现有组件中:
class CommentsCount extends React.Component { render() { return <div>{this.state.commentsCount}</div> }}
const FetchCommentsCount = withBehavior([ function* () { yield { request: ['FETCH_COMMENTS_COUNT']} const comments = yield fetchComments() yield { request: ['FETCH_COMMENTS_COUNT_SUCCESS']} this.setState({ commentsCount: comments.length }) },])(CommentsCount)
Here we are using withBehavior
, from the b-thread library, to make CommentsCount
a behavioral component. Specifically, we are making it fetch the comments and display the data once the data is ready.
在这里,我们使用来自b线程库的withBehavior
,使CommentsCount
成为行为组件。 具体来说,我们正在使它获取注释并在数据准备好后显示数据。
For simple components, this might not be such a game-changer. But let’s imagine more complex components, with lots of logic and other components inside of them.
对于简单的组件,这可能不会改变游戏规则。 但是,让我们想象一下更复杂的组件,其中包含许多逻辑和其他组件。
We might imagine the entire Netflix website as a <Netflix
/> component:
我们可以将整个Netflix网站想象为<Netflix
/>组件:
When we use this component in our app, we’d like to interact with it. Specifically, when a movie is clicked, we don’t want to start the movie immediately, but instead we want to make an HTTP request, show other data about the movie, and then start the movie.
当我们在应用程序中使用此组件时,我们希望与其进行交互。 具体来说,当单击电影时,我们不想立即启动该电影,而是希望发出HTTP请求,显示有关该电影的其他数据,然后启动该电影。
Without changing code inside the <Netflix
/> component, I’d argue that this would be impossible to achieve without it being a behavioral component.
如果不更改<Netflix
/>组件内部的代码,我认为如果没有行为组件就无法实现。
Instead let’s imagine that <Netflix
/> was developed using behavioral programming:
相反,让我们想象<Netflix
/>是使用行为编程开发的:
const NetflixWithMovieInfo = withBehavior([ function* () { // First, block the MOVIE_START from happening // within <Netflix /> until a new // FETCH_MOVIE_INFO_SUCCESS event has been requested. // The yield statement below can be read as: // wait for FETCH_MOVIE_INFO_SUCCESS while blocking MOVIE_START yield { wait: ['FETCH_MOVIE_INFO_SUCCESS'], block: ['MOVIE_START'] } }, function* () { // Here we wait for MOVIE_CLICKED, which is // triggered within <Netflix />, and we fetch our // movie info. Once that's done we request a new event // which the earlier behavior is waiting upon const movie = yield { wait: ['MOVIE_CLICKED'] } const movieInfo = yield fetchMovieInfo(movie) yield { request: ['FETCH_MOVIE_INFO_SUCCESS'], payload: movieInfo } }])(Netflix)
Above we’ve created a new NetflixWithMovieInfo
component which modifies the behavior of the <Netflix
/> component (again, without changing its source code). The addition of the above behaviors makes it so that MOVIE_C
LICKED will not trigger MOVIE
_START immediately.
上面,我们创建了一个新的NetflixWithMovieInfo
组件,该组件修改了<Netflix
/>组件的行为(同样,不更改其源代码)。 上述行为的添加使that MOVIE_C
LICKED不会立即igger MOVIE
_START。
Instead, it uses a combination of “waiting while blocking”: a wait and a block can be defined within a single yield statement.
相反,它使用“等待时阻塞”的组合:可以在单个yield语句中定义等待和阻塞 。
The picture above describes, more in detail, what is happening within our behavioral components. Each little box within the components is a yield statement. Each vertical dashed arrow represents a behavior (aka b-thread).
上图更详细地描述了我们的行为组件中正在发生的事情。 组件中的每个小方框都是yield语句。 每个垂直虚线箭头代表行为(又称b线程)。
Internally, the behavioral implementation will start by looking at all the yield statements of all b-threads at the current synchronization point, depicted using an horizontal yellow line. It will only continue to the next yield statement within a b-thread if no events in other b-threads are blocking it.
在内部,行为实现将从查看当前同步点处所有b线程的所有yield语句开始,并使用水平黄线描绘。 如果其他b线程中没有任何事件阻止它,它将仅继续到b线程中的下一个yield语句。
Since nothing is blocking MOVIE_CLICKED
, it will be requested. We can then continue to the next yield statement for the Netflix behavior. At the next synch point, the b-thread on the far right, which is waiting for MOVIE_CLICKED
, will proceed to its next yield statement.
由于没有什么阻止MOVIE_CLICKED
,因此将请求它。 然后,我们可以继续执行下一个关于Netflix行为的收益声明。 在下一个同步点,最右边的b线程正在等待MOVIE_CLICKED
,将继续执行下一个yield语句。
The middle behavior that is waiting-and-blocking does not proceed. FETCH_MOVIE_INFO_SUCCESS
was not requested by other b-threads, so it still waits-and-blocks. The next synchronization point will look something like this:
等待和阻止的中间行为不会继续。 其他b线程未请求FETCH_MOVIE_INFO_SUCCESS
,因此它仍在等待并阻塞。 下一个同步点将如下所示:
As before, we will look at all the yield statement at this synchronization point. This time, however, we cannot request MOVIE_START
because there’s another b-thread that is blocking it (the black yield statement). The Netflix component will therefore not start the movie.
和以前一样,我们将在此同步点查看所有yield语句。 但是,这一次我们无法请求MOVIE_START
因为还有另一个b线程正在阻止它(黑色yield语句)。 Netflix组件因此将无法开始播放电影。
FETCH_MOVIE_INFO_SUCCESS
on the far right, however, is free to be requested. This will unblock MOVIE_START
at the next synch point.
但是,最右边的FETCH_MOVIE_INFO_SUCCESS
是免费的。 这将在下一个同步点取消阻止MOVIE_START
。
All this in practice allowed us to change the order of things happening within other components, without directly modifying their code. We were able to block certain events from firing until other conditions were met in other components.
实际上,所有这些使我们能够更改其他组件中发生的事情的顺序,而无需直接修改它们的代码。 我们能够阻止某些事件触发,直到在其他组件中满足其他条件为止。
This changes the way we might think of programming: not necessarily a set of statements executed in order, but rather an interleaving of yield statements all synchronized through specific event semantics.
这改变了我们对编程的思考方式:不一定是按顺序执行的一组语句,而是交织了所有通过特定事件语义同步的yield语句。
Here’s a simple animation depicting the way b-threads are executed and interwoven at runtime.
这是一个简单的动画,描绘了b线程在运行时执行和交织的方式。
无需更改旧代码即可编程 (Programming without changing old code)
There is another way we can understand this programming idiom. We can compare the way we currently program as specifications change, versus how it would be done with behavioral programming.
我们可以用另一种方式来理解这种编程习惯。 我们可以将当前随着规范变化而编程的方式与行为编程的方式进行比较。
In the above caption, we imagine how behavior may be added to a non-behavioral program. We start with a program described only using three black rectangles (on the left).
在上面的标题中,我们想象了如何将行为添加到非行为程序中。 我们从仅使用三个黑色矩形(左侧)描述的程序开始。
As specifications change, we realize we need to modify the program and add new behavior in various sections of the program, depicted as newly added colored rectangles. We continue doing this as requirements for our software change.
随着规范的变化,我们意识到我们需要修改程序并在程序的各个部分添加新行为,以新添加的彩色矩形表示。 作为软件更改的要求,我们将继续这样做。
Every addition of behavior requires us to change code that was written, which possibly litters the old behavior with bugs. Furthermore, if the program we are changing is part of various other modules used by different people, we might be introducing unwanted behavior to their software. Finally, it may not be possible to change specific programs as they might be distributed as libraries with licensed source code.
行为的每次添加都要求我们更改所编写的代码,这可能会用错误掩盖旧行为。 此外,如果我们要更改的程序是不同人使用的其他模块的一部分,那么我们可能会在他们的软件中引入不必要的行为。 最后,可能无法更改特定程序,因为它们可能作为具有许可源代码的库分发。
In the above figure, we see how the same program-modifications can be achieved using behavioral programming idioms. We still start with our three rectangles on the left as we did before. But as new specifications arise, we don’t modify them. Instead we add new b-threads, represented as columns.
在上图中,我们看到了如何使用行为编程习惯来实现相同的程序修改。 我们仍然像以前一样从左侧的三个矩形开始。 但是随着新规范的出现,我们不会对其进行修改。 相反,我们添加了新的b线程,以列表示。
The resulting program is the same, although constructed in a very different way. One of the advantages of the behavioral approach is that we don’t have to modify old code as requirements change.
生成的程序是相同的,尽管构造方式非常不同。 行为方法的优点之一是,随着需求的变化,我们不必修改旧代码。
You can also imagine developing each b-thread in parallel, possibly by different people in a large organization, since they do not directly depend on each other.
您也可以想象大型机构中的不同人员可能并行开发每个b线程,因为它们并不直接相互依赖。
The benefit of this approach also seems to be with packaging: we can change the behavior of a library without needing to access or modify its source-code.
这种方法的好处似乎还在于打包:我们可以更改库的行为,而无需访问或修改其源代码。
API不仅作为道具,而且作为事件 (APIs not only as props, but as events)
Currently, the only way for a React component to communicate with the outside world is via props (apart from the Context API).
当前,React组件与外界通信的唯一方法是通过props(除了Context API)。
By making a component behavioral, instead of using props, we tell the outside world about when things happen within the component by yielding events.
通过使组件具有行为性,而不是使用道具,我们通过产生事件来告知外界组件中何时发生事件。
To allow other developers to interact with the behavior of a component, we must therefore document the events that it requests, the events it waits for, and finally the events it blocks.
因此,为了允许其他开发人员与组件的行为进行交互,我们必须记录其请求的事件,其等待的事件以及最终阻止的事件。
Events become the new API.
事件成为新的API。
For instance, in a non-behavioral Counter
component, we tell the outside world when the counter is incremented and what the current count is, using an onIncrement
prop:
例如,在一个非行为Counter
组件中,我们使用onIncrement
道具告诉外界计数器何时递增以及当前计数是onIncrement
:
class Counter extends React.Component { state = { currentCount: 0 } handleClick = () => { this.setState(prevState => ({ currentCount: prevState.currentCount + 1 }), () => { this.props.onIncrement(this.state.currentCount) }) } render() { {this.state.currentCount} <button onClick={this.handleClick}>+</button> }}
<Counter onIncrement={(currentCount) => console.log(currentCount) }/>
What if we want to do something else before the counter’s state gets incremented? Indeed we could add a new prop such as onBeforeIncrement
, but the point is that we don’t want to add props and refactor code every time a new specific arises.
如果我们想在计数器状态递增之前做其他事情怎么办? 确实,我们可以添加一个新的道具,例如onBeforeIncrement
,但要点是,我们不想在每次出现新的道具时都添加道具和重构代码。
If we transform it into a behavioral component we can avoid refactoring when new specifications emerge:
如果我们将其转换为行为组件,则可以避免在出现新规范时进行重构:
class Counter extends React.Component { state = { currentCount: 0 } handleClick = () => { bp.event('CLICKED_INCREMENT') } render() { {this.state.currentCount} <button onClick={this.handleClick}>+</button> }}
const BehavioralCounter = withBehavior([ function* () { yield { wait: ['CLICKED_INCREMENT'] } yield { request: ['UPDATE_CURRENT_COUNT'] }
this.setState(prevState => ({ currentCount: prevState.currentCount + 1 }), () => { this.props.onIncrement(this.state.currentCount) }) }])(Counter)
Notice how we moved the logic for when the state is updated inside a b-thread. Furthermore, before the update actually takes place, a new event UPDATE_CURRENT_COUNT
is requested.
注意,如何在b线程中更新状态时如何移动逻辑。 此外,在实际进行更新之前,请求一个新事件UPDATE_CURRENT_COUNT
。
This effectively allows other b-threads to block the update from happening.
这有效地允许其他b线程阻止更新的发生。
Components can also be encapsulated and shared as different packages, and users can add behavior as they see fit.
组件也可以封装和共享为不同的包,用户可以根据自己的喜好添加行为。
// package-name: movies-listexport const function MoviesList() { ...}
// package-name: movies-list-with-paginationexport const MoviesListWithPagination = pipe( withBehavior(addPagination))(MoviesList)
// package-name: movies-list-with-pagination-logicexport const MoviesListWithDifferentPaginationLogic = pipe( withBehavior(changePaginationLogic))(MoviesListWithPagination)
Again this is different from simply enhancing a component, as a regular HOC would do. We can block certain things from happening in the components we extend from, effectively modifying their behavior.
再次,这不同于常规HOC所做的简单地增强组件。 我们可以阻止某些事情在扩展组件中发生,从而有效地修改其行为。
结论 (Conclusion)
This new programming idiom might feel uncomfortable at first, but it seems to alleviate a prominent issue we have when using UI components: it is hard to reuse components, because they don’t blend with the environment they were put into.
刚开始时,这种新的编程习惯可能会让您感到不舒服,但是它似乎减轻了我们在使用UI组件时遇到的一个突出问题: 很难重用组件,因为它们不会与所放置的环境融合在一起。
In the future, perhaps using these behavioral concepts, we will be able to add new behavior to apps by simply mounting new components. Stuff like this will be possible:
将来,也许使用这些行为概念,我们将能够通过简单地安装新组件来向应用程序添加新行为。 这样的东西将是可能的:
<Environment> <Netflix /> <Twitter /> <WaitForTwitterBeforeNetflix /> <OnTwitterClickShowLoader /></Environment>
Additionally, events don’t need to pollute the whole app and can be broadcast only within a specific environment.
此外,事件并不需要污染整个应用程序,而只能在特定环境中广播。
Thanks for reading! If you’re interested in an actual implementation of behavioral programming, please see my current work in progress library that works with React: https://github.com/lmatteis/b-thread. The Behavioral Programming homepage also contains various implementations.
谢谢阅读! 如果您对行为编程的实际实现感兴趣,请参见我当前与React一起使用的进度库: https : //github.com/lmatteis/b-thread 。 行为编程主页还包含各种实现。
For more information on this exciting new concept, I suggest you read the scientific papers on Behavioral Programming or check some of my other articles on the subject.
有关此令人兴奋的新概念的更多信息,建议您阅读有关行为编程的科学论文,或查看我 有关该主题的 其他文章 。
翻译自: https://www.freecodecamp.org/news/an-intro-to-behavioral-programming-with-react-request-wait-and-block-ad876e2d235e/
react发送和接收请求
最后
以上就是怕孤独超短裙为你收集整理的react发送和接收请求_React行为编程简介:请求,等待和阻止 React行为编程简介:请求,等待和阻止 (An intro to Behavioral Programming with React: request, wait, and block)的全部内容,希望文章能够帮你解决react发送和接收请求_React行为编程简介:请求,等待和阻止 React行为编程简介:请求,等待和阻止 (An intro to Behavioral Programming with React: request, wait, and block)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复