简体   繁体   English

React.js 中声明式和命令式的区别?

[英]Difference between declarative and imperative in React.js?

Recently I've been studying a lot about the functionality and the ways to use the Facebook JavaScript library React.js.最近我一直在研究 Facebook JavaScript 库 React.js 的功能和使用方法。 When speaking of its differences to the rest of the JavaScript world often the two programming styles declarative and imperative are mentioned.当谈到它与 JavaScript 世界其他部分的区别时,通常会提到declarative式和imperative两种编程风格。

What's the difference between both?两者有什么区别?

A declarative style, like what react has, allows you to control flow and state in your application by saying "It should look like this".声明式风格,就像 react 一样,允许您通过说“它应该看起来像这样”来控制应用程序中的流程和状态。 An imperative style turns that around and allows you to control your application by saying "This is what you should do".命令式风格可以扭转这种局面,并允许您通过说“这是您应该做的”来控制您的应用程序。

The benefit of declarative is that you don't get bogged down in the implementation details of representing the state.声明式的好处是您不会陷入表示状态的实现细节中。 You're delegating the organizational component of keeping your application views consistent so you just have to worry about state.您正在委派保持应用程序视图一致的组织组件,因此您只需要担心状态。

Imagine you have a butler, who is kind of a metaphor for a framework.想象一下,你有一个管家,他是一种框架的隐喻。 And you would like to make dinner.你想做晚饭。 In an imperative world, you would tell them step by step how to make dinner.在一个命令式的世界里,你会一步一步地告诉他们如何做晚餐。 You have to provide these instructions:您必须提供以下说明:

Go to the kitchen
Open fridge
Remove chicken from fridge
...
Bring food to the table

In a declarative world, you would simply describe what you want在声明式世界中,您只需描述您想要的内容

I want dinner with chicken.

If your butler doesn't know how to make chicken, then you cannot operate in a declarative style.如果您的管家不知道如何制作鸡肉,那么您就不能以声明式的方式进行操作。 Just like if Backbone doesn't know how to mutate itself to do a certain task, you can't just tell it to do that task.就像如果 Backbone 不知道如何变异自己来完成某项任务一样,您不能只告诉它执行该任务。 React is able to be declarative because it "knows how to make chicken", for example.例如,React 能够是声明性的,因为它“知道如何制作鸡肉”。 Compared to Backbone, which only knows how to interface with the kitchen.与只知道如何与厨房交互的 Backbone 相比。

Being able to describe the state reduces the surface area for bugs dramatically, which is a benefit.能够描述状态极大地减少了错误的表面积,这是一个好处。 On the other hand, you might have less flexibility in how things occur because you're delegating or abstracting away how you implement the state.另一方面,您可能在事情发生方式上的灵活性较低,因为您正在委派或抽象出您如何实现状态。

Imagine a simple UI component, such as a "Like" button.想象一个简单的 UI 组件,例如“Like”按钮。 When you tap it, it turns blue if it was previously grey, and grey if it was previously blue.当你点击它时,如果它以前是灰色的,它会变成蓝色,如果它以前是蓝色的,它就会变成灰色。

The imperative way of doing this would be:这样做的必要方法是:

if( user.likes() ) {
        if( hasBlue() ) {
            removeBlue();
            addGrey();
        } else {
            removeGrey();
            addBlue();
        }
    }

Basically, you have to check what is currently on the screen and handle all the changes necessary to redraw it with the current state, including undoing the changes from the previous state.基本上,您必须检查屏幕上当前的内容并处理所有必要的更改,以使用当前状态重绘它,包括撤消对先前状态的更改。 You can imagine how complex this could be in a real-world scenario.您可以想象在现实世界中这可能是多么复杂。

In contrast, the declarative approach would be:相比之下,声明性方法将是:

return this.state.liked ? <blueLike /> : <greyLike />;

Because the declarative approach separates concerns, this part of it only needs to handle how the UI should look in a sepecific state, and is therefore much simpler to understand.因为声明式方法分离了关注点,这部分只需要处理 UI 在特定状态下的外观,因此更容易理解。

It is best to compare React (declarative) and JQuery (imperative) to show you the differences.最好比较 React(声明式)和 JQuery(命令式)以向您展示差异。

In React, you only need to describe the final state of your UI in the render() method, without worrying about how to transition from previous UI state to the new UI state.在 React 中,你只需要在render()方法中描述你的 UI 的最终状态,而不用担心如何从之前的 UI 状态转换到新的 UI 状态。 Eg,例如,

render() {
  const { price, volume } = this.state;
  const totalPrice = price * volume;

  return (
    <div>
      <Label value={price} className={price > 100 ? 'expensive' : 'cheap'} ... />
      <Label value={volume} className={volume > 1000 ? 'high' : 'low'} ... />
      <Label value={totalPrice} ... />
      ...
    </div>
  )
}

On the other hand, JQuery requires you to transition your UI state imperatively, eg, selecting the label elements and update their text and CSS:另一方面,JQuery 要求您强制转换 UI 状态,例如,选择标签元素并更新它们的文本和 CSS:

updatePrice(price) {
  $("#price-label").val(price);
  $("#price-label").toggleClass('expansive', price > 100);
  $("#price-label").toggleClass('cheap', price < 100);

  // also remember to update UI depending on price 
  updateTotalPrice();
  ... 
}

updateVolume(volume) {
  $("#volume-label").val(volume);
  $("#volume-label").toggleClass('high', volume > 1000);
  $("#volume-label").toggleClass('low', volume < 1000);
  
  // also remember to update UI depending on volume
  updateTotalPrice();
  ... 
}

updateTotalPrice() {
  const totalPrice = price * volume;
  $("#total-price-label").val(totalPrice);
  ...
}

In the real world scenario, there will be many more UI elements to be updated, plus their attributes (eg, CSS styles, and event listeners), etc. If you do this imperatively using JQuery, it will become complex and tedious;在现实世界的场景中,会有更多的 UI 元素需要更新,以及它们的属性(例如 CSS 样式和事件侦听器)等。如果您使用 JQuery 强制执行此操作,则会变得复杂和乏味; it is easy to forget to update some parts of the UI, or forget to remove old event handlers (cause memory leak or handler fires multiple times ), etc. This is where bugs happen, ie, UI state and the model state are out of sync.很容易忘记更新 UI 的某些部分,或者忘记删除旧的事件处理程序(导致内存泄漏或处理程序多次触发)等。这就是 bug 发生的地方,即 UI 状态和模型状态不在同步。

States out of sync will never happen to React's declarative approach, because we only need to update the model state, and React is responsible to keep the UI and model states in sync.状态不同步不会发生在 React 的声明式方法中,因为我们只需要更新模型状态,而 React 负责保持 UI 和模型状态同步。

  • Under the hook, React will updates all changed DOM elements using imperative code.在这个钩子下,React 将使用命令式代码更新所有更改的 DOM 元素。

You may also read my answer for What is the difference between declarative and imperative paradigm in programming?您还可以阅读我对编程中声明式范式和命令式范式有什么区别的回答? . .

PS: from above jQuery example, you may think what if we put all the DOM manipulations in a updateAll() method, and call it every time when any of our model state changes, and the UI will never be out of sync. PS:从上面的 jQuery 示例中,您可能会想,如果我们将所有 DOM 操作放在一个updateAll()方法中,并且每次模型状态发生变化时调用它,UI 将永远不会不同步。 You are correct, and this is effectively what React does, the only difference is that jQuery updateAll() will cause many unnecessary DOM manipulations, but React will only update changed DOM elements using its Virtual DOM Diffing Algorithm .你是对的,这实际上是 React 所做的,唯一的区别是 jQuery updateAll()会导致许多不必要的 DOM 操作,但 React 只会使用其Virtual DOM Diffing Algorithm更新更改的 DOM 元素。

This is great analogy:这是一个很好的类比:

*An imperative response : Go out of the north exit of the parking lot and take a left. *当务之急:从停车场北口出来左转。 Get on I-15 south until you get to the Bangerter Highway exit.沿 I-15 向南行驶,直到您到达 Bangerter 高速公路出口。 Take a right off the exit like you're going to Ikea.就像你要去宜家一样,从出口右转。 Go straight and take a right at the first light.直走并在第一个红绿灯处右转。 Continue through the next light then take your next left.继续通过下一个灯,然后左转。 My house is #298.我的房子是#298。

A declarative response : My address is 298 West Immutable Alley, Draper Utah 84020*声明性回复:我的地址是 298 West Immutable Alley, Draper Utah 84020*

https://tylermcginnis.com/imperative-vs-declarative-programming/ https://tylermcginnis.com/imperative-vs-declarative-programming/

Imperative code instructs JavaScript on how it should perform each step.命令式代码指示 JavaScript 如何执行每个步骤。 With declarative code, we tell JavaScript what we want to be done, and let JavaScript take care of performing the steps.使用声明性代码,我们告诉 JavaScript 我们想要做什么,并让 JavaScript 负责执行这些步骤。

React is declarative because we write the code that we want and React is in charge of taking our declared code and performing all of the JavaScript/DOM steps to get us to our desired result. React 是声明性的,因为我们编写了我们想要的代码,而 React 负责获取我们声明的代码并执行所有 JavaScript/DOM 步骤以使我们达到我们想要的结果。

A real-life parallel in the imperative world would be entering a bar for a beer, and giving the following instructions to the bartender:在命令式世界中,现实生活中的一个相似之处是进入酒吧喝啤酒,并向调酒师发出以下指示:

--Take a glass from the shelf --从架子上拿一杯

--Put the glass in front of the draft --把玻璃放在草稿前

--Pull down the handle until the glass is full --拉下把手直到杯子满

--Pass me the glass. ——把杯子递给我。

In the declarative world, instead, you would just say: "Beer, please."相反,在声明式世界中,您只需说:“请喝啤酒。”

The declarative approach of asking for a beer assumes that the bartender knows how to serve one, and that is an important aspect of the way declarative programming works.要求啤酒的声明式方法假设调酒师知道如何为啤酒服务,这是声明式编程工作方式的一个重要方面。

In declarative programming, developers only describe what they want to achieve and there's no need to list all the steps to make it work.在声明式编程中,开发人员只描述他们想要实现的目标,而无需列出使其工作的所有步骤。

The fact that React offers a declarative approach makes it easy to use, and consequently, the resulting code is simple, which often leads to fewer bugs and more maintainability. React 提供声明式方法这一事实使其易于使用,因此生成的代码很简单,这通常会导致更少的错误和更高的可维护性。

Since React follows a declarative paradigm, and there's no need to tell it how to interact with the DOM;由于 React 遵循声明式范式,因此无需告诉它如何与 DOM 交互; you just DECLARE what you want to see on the screen and React does the job for you.你只需声明你想在屏幕上看到的内容,React 就会为你完成这项工作。

Declarative programming is a style of programming where applications are structured in a way that prioritizes describing what should happen over defining how it should happen.声明式编程是一种编程风格,其中应用程序的结构方式优先于描述应该发生的事情,而不是定义应该如何发生。

In order to understand declarative programming, Let's compare it with imperative programming (style of programming that's only concerned with how to achieve results with code).为了理解声明式编程,让我们将其与命令式编程(只关心如何用代码实现结果的编程风格)进行比较。

Example: making a string URL-friendly.示例:使字符串 URL 友好。 Typically, this can be accomplished by replacing all of the spaces in a string with hyphens, since spaces are not URL-friendly.通常,这可以通过用连字符替换字符串中的所有空格来完成,因为空格不是 URL 友好的。 First, An imperative approach to this task:首先,这个任务的命令式方法:

const string = "difference between declarative and imperative in react.js";
const urlFriendly = "";
for (var i = 0; i < string.length; i++) {
    if (string[i] === " ") {
      urlFriendly += "-";
    } else {
      urlFriendly += string[i];
    }
}
console.log(urlFriendly); // "difference-between-declarative-and-imperative-in-react-js"

In this example, we loop through every character in the string, replacing spaces as they occur.在此示例中,我们遍历字符串中的每个字符,并在出现空格时替换它们。 The structure of this program is only concerned with how such a task can be achieved.这个程序的结构只关心如何完成这样的任务。 We use a for loop and an if statement and set values with an equality operator.我们使用 for 循环和 if 语句并使用相等运算符设置值。 Just looking at the code alone does not tell us much as imperative programs require lots of comments in order to understand what's going on.仅仅看代码并不能告诉我们太多,因为命令式程序需要大量注释才能理解发生了什么。

Now let's look at a declarative approach to the same problem:现在让我们看一下针对同一问题的声明性方法:

const string = "Difference between declarative and imperative in React.js?";
const urlFriendly = string.replace(/ /g, "-");
console.log(urlFriendly);

Here we are using string.replace along with a regular expression to replace all instances of spaces with hyphens.在这里,我们使用string.replace和正则表达式来用连字符替换所有空格实例。 Using string.replace is a way of describing what's supposed to happen: spaces in the string should be replaced.使用string.replace是描述应该发生的事情的一种方式:字符串中的空格应该被替换。 The details of how spaces are dealt with are abstracted away inside the replace function.如何处理空间的细节在替换函数中被抽象出来。

In a declarative program, the syntax itself describes what should happen, and the details of how things happen are abstracted away.在声明式程序中,语法本身描述了应该发生的事情,而事情发生的细节被抽象掉了。

Essentially, declarative programming produces applications that are easier to reason about, and when it's easier to reason about an application, that application is easier to scale.从本质上讲,声明式编程产生的应用程序更容易推理,当对应用程序更容易推理时,该应用程序更容易扩展。 Additional details about the declarative programming paradigm can be found at the Declarative Programming wiki .有关声明式编程范例的更多详细信息,请参见声明式编程 wiki

Now, let's consider the task of building a document object model.现在,让我们考虑构建文档对象模型的任务。 An imperative approach would be concerned with how the DOM is constructed:一种命令式方法将关注 DOM 的构造方式:

const target = document.getElementById("target");
const wrapper = document.createElement("div");
const headline = document.createElement("h1");
wrapper.id = "welcome";
headline.innerText = "Hello World";
wrapper.appendChild(headline);
target.appendChild(wrapper);

This code is concerned with creating elements, setting elements, and adding them to the document.此代码涉及创建元素、设置元素并将它们添加到文档中。 It would be very hard to make changes, add features, or scale 10,000 lines of code where the DOM is constructed imperatively.在强制构建 DOM 的情况下,很难进行更改、添加功能或扩展 10,000 行代码。

Now let's take a look at how we can construct a DOM declaratively using a React component:现在让我们看看如何使用 React 组件以声明方式构造 DOM:

const { render } = ReactDOM;
const Welcome = () => (
   <div id="welcome">
      <h1>Hello World</h1>
   </div>
);

render(<Welcome />, document.getElementById("target"));

React is declarative. React 是声明式的。 Here, the Welcome component describes the DOM that should be rendered.在这里,Welcome 组件描述了应该呈现的 DOM。 The render function uses the instructions declared in the component to build the DOM, abstracting away the details of how the DOM is to be rendered.渲染函数使用组件中声明的指令来构建 DOM,抽象出如何渲染 DOM 的细节。 We can clearly see that we want to render our Welcome component into the element with the ID of target我们可以清楚地看到我们想要将 Welcome 组件渲染到 ID 为 target 的元素中

Source: Modern Patterns for Developing React Apps来源: 开发 React 应用程序的现代模式

Declarative programming is a programming paradigm … that expresses the logic of a computation without describing its control flow.声明式编程是一种编程范式……它表达了计算的逻辑而不描述其控制流。

Imperative programming is a programming paradigm that uses statements that change a program's state.命令式编程是一种编程范式,它使用改变程序状态的语句。

ref link:- https://codeburst.io/declarative-vs-imperative-programming-a8a7c93d9ad2参考链接:- https://codeburst.io/declarative-vs-imperative-programming-a8a7c93d9ad2

  • Declarative is allowed you to control all view.声明式允许您控制所有视图。 (like as state management) (就像状态管理一样)
  • the Imperative is allowed you control around view.命令式允许您控制视图。 (like as $(this)) (就像 $(this) 一样)

I'll start with an analogy: I have two cars, in my two cars I want the temperatue inside my car to be normal room temperature ~ 72°F.我将从一个类比开始:我有两辆车,在我的两辆车中,我希望车内的温度为正常室温~72°F。 In the first (older) car, there's two knobs to control the temperature (1 knob to control the temperature and 1 knob to control the airflow).在第一辆(较旧的)汽车中,有两个旋钮用于控制温度(一个旋钮用于控制温度,一个旋钮用于控制气流)。 When it gets too hot, I have to adjust the first knob to lower the temperature and maybe change the airflow) and vice verse if it's too cold.当它变得太热时,我必须调整第一个旋钮以降低温度并可能改变气流)如果太冷则反之亦然。 This is imperative work!这是一项势在必行的工作! I have to manage the knobs myself.我必须自己管理旋钮。 In my second (newer) car, I can set/declare the temperature.在我的第二辆(较新)汽车中,我可以设置/声明温度。 Which means I don't have to fiddle with the knobs to adjust the temperature my car knows I declare/set it to 72°F and my car will do the imperative work to get to that state.这意味着我不必摆弄旋钮来调整我的汽车知道的温度,我宣布/将其设置为 72°F,我的汽车将完成必要的工作以达到该状态。

React is the same, you declare the markup/template and stat then React does the imperative work to keep the DOM in sync with your app. React 是一样的,你声明标记/模板和 stat 然后 React 做必要的工作来保持 DOM 与你的应用程序同步。

<button onClick={activateTeleporter}>Activate Teleporter</button>

Instead of using .addEventListener() to set up event handling, we declare what we want.我们不使用.addEventListener()来设置事件处理,而是声明我们想要的。 When the button is clicked, it'll run the activateTeleporter function.单击按钮时,它将运行activateTeleporter函数。

Declarative vs Imperative声明式与命令式

Declarative Programming is like asking your friend to paint your House.声明式编程就像让你的朋友画你的房子。 You don't care how they clean it,what colour they use to paint,How many resources they used to complete it`.你不在乎他们如何清洁它,他们用什么颜色来绘画,他们用了多少资源来完成它`。

//Declarative For Searching element from an array
  array.find(item)

The opposite of declarative is imperative.声明式的反面是命令式的。 A common example of an imperative approach is is you told your friend exactly what to do to paint your House.命令式方法的一个常见例子是你告诉你的朋友确切地做什么来粉刷你的房子。

  • Wash the house with detergent.用清洁剂清洗房子。
  • Use Narolac paint or asian paint使用 Narolac 油漆或亚洲油漆
  • Paint the roof with Green color.用绿色油漆屋顶。
  • Get 3 members to contract,etc.获得3名成员签约等。

//Imperative Algo //命令式算法

def imperative_search(array, item)
  for i in array do
    if i == item
      return item
    end
  end
  return false
end

This is my understanding so far:这是我目前的理解:

Declarative code (almost?) always is a layer of abstraction above code that is more imperative in nature.声明性代码(几乎?)始终是代码之上的抽象层,本质上更具有命令性。

React allows you to write declarative code that is a layer of abstraction above the imperative code that interacts with the DOM directly (eg. the diffing algorithm ). React 允许您编写声明性代码,它是直接与 DOM 交互的命令式代码(例如diffing 算法)之上的抽象层。 If you need to write imperative code (ie. interact with the DOM directly) React provides Refs as an escape hatch .如果您需要编写命令式代码(即直接与 DOM 交互),React 提供Refs 作为逃生舱口

Explaining every bit of steps is an Imperative approach eg We have to create a paragraph tag with Hello World!解释每一步步骤是一种命令式方法,例如我们必须使用 Hello World 创建一个段落标签! text inside.里面的文字。

//Imperative 

const para = document.createElement('p');
para.innerText = 'Hello World !';
document.querySelector('#root').appendChild(para);

Defining desired end target state without specifying exact procedure.在不指定确切过程的情况下定义所需的最终目标状态。 ie p tag with text, without telling to createElement or innerText即带有文本的 p 标记,无需告诉 createElement 或 innerText

 //Declarative 

 import React from "react"; 
 import ReactDOM from "react-dom"; 
 
 const App = () =>{
  return(<p>Hello World !</p>);
 }

 ReactDOM.render(<App />, document.getElementById("root"));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 React.js中所有者和父组件之间的区别是什么 - What is the difference between owner and parent component in React.js 在React.js中使用this.props和props有什么区别? - What is the difference between using this.props and props in React.js? React.js中ES5和ES6构造函数之间的区别 - Difference between ES5 and ES6 constructors in React.js 在React.js中获取两个日期之间的天差 - Getting days difference between two dates in React.js React(来自Facebook的应用程序框架)和react.js(JS的反应性扩展)之间有什么区别/相似之处? - What are the difference/similarities between React (app framework from Facebook) and react.js (reactive extensions for JS)? React.js:使用React.render()和React.createClass()的渲染传递子组件之间的区别? - React.js: Difference between passing in the subcomponents with React.render() and with React.createClass()'s render? 安装React.js和Node.js以及为库使用Script标签之间的区别 - Difference between installing React.js and Node.js and Using Script tag for library 使用React.js中的moment.js计算并显示两个日期之间的差异? - Calculate and display difference between two dates using moment.js in React.js? 直接在 this.setState 中返回对象字面量与原始值的区别? (反应.JS) - Difference between returning object literal vs raw values directly in this.setState? (React.JS) 在兄弟 React.js 之间传递索引 - Passing index between sibilings React.js
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM