- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
React在前端界一直很流行,而且学起来也不是很难,只需要学会JSX、理解State和Props,然后就可以愉快的玩耍了,但想要成为React的专家你还需要对React有一些更深入的理解,希望本文对你有用。
React在前端界一直很流行,而且学起来也不是很难,只需要学会JSX、理解State
VàProps
,然后就可以愉快的玩耍了,但想要成为React的专家你还需要对React有一些更深入的理解,希望本文对你有用。
这是Choerodon的一个前端页面
在复杂的前端项目中一个页面可能包含上百个状态,对React框架理解得更精细一些对前端优化很重要。曾经这个页面点击一条记录展示详情会卡顿数秒,而这仅仅是前端渲染造成的。
为了能够解决这些问题,开发者需要了解React组件从定义到在页面上呈现(然后更新)的整个过程。
React在编写组件时使用混合HTML
VàJavaScript
的一种语法(称为JSX)。 但是,浏览器对JSX及其语法一无所知,浏览器只能理解纯JavaScript
,因此必须将JSX转换为HTML
。 这是一个div的JSX代码,它有一个类和一些内容:
文本
在React中将这段jsx变成普通的js之后它就是一个带有许多参数的函数调用:
React.createElement( 'div', { className: 'cn' }, '文本' );
React.createElement( 'div', { className: 'cn' }, ['Content 1!', React.createElement('br'), 'Content 2!'] ) 它的第一个参数是一个字符串,对应html中的标签名,第二个参数是它的所有属性所构成的对象,当然,它也有可能是个空对象,剩下的参数都是这个元素下的子元素,这里的文本也会被当作一个子元素,所以第三个参数是 `“文本”` 。 到这里你应该就能想象这个元素下有更多`children`的时候会发生什么。 ```html 文本1
文本2
React.createElement( 'div', { className: 'cn' }, '文本1', // 1st child React.createElement('br'), // 2nd child '文本1' // 3rd child )
目前的函数有五个参数:元素的类型,全部属性的对象和三个子元素。 由于一个đứa trẻ
也是React已知的HTML
标签,因此它也将被解释成函数调用。
到目前为止,本文已经介绍了两种类型的đứa trẻ
参数,一种是sợi dây
纯文本,一种是调用其他的React.createElement
函数。其实,其他值也可以作为参数,比如: - 基本类型 false,null,undefined和 true - 数组 - React组件
使用数组是因为可以将子组件分组并作为一个参数传递:
当然,React的强大功能不是来自`HTML`规范中描述的标签,而是来自用户创建的组件,例如: ```js function Table({ rows }) { return ( {rows.map(row => ( {row.title} ))}
); }
组件允许开发者将模板分解为可重用的块。在上面的“纯函数”组件的示例中,组件接受一个包含表行数据的对象数组,并返回React.createElement
对table元素及其行作为子元素的单个调用 。
每当开发者将组件放入JSX布局中时它看上去是这样的:
但从浏览器角度,它看到的是这样的:
React.createElement(Table, { rows: rows });
请注意,这次的第一个参数不是以sợi dây
描述的HTML元素,而是组件的引用(即函数名)。第二个参数是传入该组件的props
sự vật.
现在,浏览器已经将所有JSX组件转换为纯JavaScript
,现在浏览器获得了一堆函数调用,其参数是其他函数调用,还有其他函数调用……如何将它们转换为构成网页的DOM元素?
为此,开发者需要使用ReactDOM
库及其render
方法:
function Table({ rows }) { /* ... */ } // 组件定义 // 渲染一个组件 ReactDOM.render( React.createElement(Table, { rows: rows }), // "创建" 一个 component document.getElementById('#root') // 将它放入DOM中 );
khiReactDOM.render
被调用时,React.createElement
最终也会被调用,它返回以下对象:
// 这个对象里还有很多其他的字段,但现在对开发者来说重要的是这些。 { type: Table, props: { rows: rows }, // ... }
这些对象构成了React意义上的Virtual DOM
它们将在所有进一步渲染中相互比较,并最终转换为真正的DOM(与Virtual DOM对比)。
这是另一个例子:这次有一个div具有class属性和几个子节点:
React.createElement( 'div', { className: 'cn' }, 'Content 1!', 'Content 2!', );
变成:
{ type: 'div', props: { className: 'cn', children: [ 'Content 1!', 'Content 2!' ] } }
所有的传入的展开函数,也就是React.createElement
除了第一第二个参数剩下的参数都会在props
对象中的children
属性中,不管传入的是什么函数,他们最终都会作为children
传入props
ở giữa.
而且,开发者可以直接在JSX代码中添加children
属性,将子项直接放在children
中,结果仍然是相同的:
在Virtual DOM对象被建立出来之后ReactDOM.render
会尝试按以下规则把它翻译成浏览器能够看得懂的DOM节点: - nếu như
Virtual DOM对象中的type属性是一个string类型的tag名称,就
创建一个tag,包含props里的全部属性。 - nếu như
Virtual DOM对象中的type属性是一个函数或者class,就
调用它,它返回的可能还是一个Virtual DOM然后将结果继续递归调用此过程。 - nếu như
props中有children属性,就
对children中的每个元素进行以上过程,并将返回的结果放到父DOM节点中。
最后,浏览器获得了以下HTML(对于上述table的例子):
Title ...
接下浏览器要“重建”一个DOM节点,如果浏览器要更新一个页面,显然,开发者并不希望替换页面中的全部元素,这就是React真正的魔法了。如何才能实现它?先从最简单的方法开始,重新调用这个节点的ReactDOM.render
phương pháp.
// 第二次调用 ReactDOM.render( React.createElement(Table, { rows: rows }), document.getElementById('#root') );
这一次,上面的代码执行逻辑将与看到的代码不同。React不是从头开始创建所有DOM节点并将它们放在页面上,React将使用“diff”算法,以确定节点树的哪些部分必须更新,哪些部分可以保持不变。
那么它是怎样工作的?只有少数几个简单的情况,理解它们将对React程序的优化有很大帮助。请记住,接下来看到的对象是用作表示React Virtual DOM中节点的对象。
▌Case 1:type是一个字符串,type在调用之间保持不变,props也没有改变。
// before update { type: 'div', props: { className: 'cn' } } // after update { type: 'div', props: { className: 'cn' } }
这是最简单的情况:DOM保持不变。
▌Case 2:type仍然是相同的字符串,props是不同的。
// before update: { type: 'div', props: { className: 'cn' } } // after update: { type: 'div', props: { className: 'cnn' } }
由于type仍然代表一个HTML元素,React知道如何通过标准的DOM API调用更改其属性,而无需从DOM树中删除节点。
▌Case 3:type已更改为不同的组件String或从String组件更改为组件。
// before update: { type: 'div', props: { className: 'cn' } } // after update: { type: 'span', props: { className: 'cn' } }
由于React现在看到类型不同,它甚至不会尝试更新DOM节点:旧元素将与其所有子节点一起被删除(unmount)。因此,在DOM树上替换完全不同的元素的代价会非常之高。幸运的是,这在实际情况中很少发生。
重要的是要记住React使用===(三等)来比较type值,因此它们必须是同一个类或相同函数的相同实例。
下一个场景更有趣,因为这是开发者最常使用React的方式。
▌Case 4:type是一个组件。
// before update: { type: Table, props: { rows: rows } } // after update: { type: Table, props: { rows: rows } }
你可能会说,“这好像没有任何变化”,但这是不对的。
如果type是对函数或类的引用(即常规React组件),并且启动了树diff比较过程,那么React将始终尝试查看组件内部的所有đứa trẻ
以确保render
的返回值没有更改。即在树下比较每个组件 - 是的,复杂的渲染也可能变得昂贵!
除了上面描述的四种常见场景之外,当元素有多个子元素时,开发者还需要考虑React的行为。假设有这样一个元素:
// ... props: { children: [ { type: 'div' }, { type: 'span' }, { type: 'br' } ] }, // ...
开发者开发者想将它重新渲染成这样(span
Vàphân chia
交换了位置):
// ... props: { children: [ { type: 'span' }, { type: 'div' }, { type: 'br' } ] }, // ...
那么会发生什么?
当React看到里面的任何数组类型的props.children
,它会开始将它中的元素与之前看到的数组中的元素按顺序进行比较:index 0将与index 0,index 1与index 1进行比较,对于每对子元素,React将应用上述规则集进行比较更新。在以上的例子中,它看到phân chia
变成一个span
这是一个情景3中的情况。但这有一个问题:假设开发者想要从1000行表中删除第一行。React必须“更新”剩余的999个孩子,因为如果与先前的逐个索引表示相比,他们的内容现在将不相等。
幸运的是,React有一种内置的方法来解决这个问题。如果元素具有chìa khóa
属性,则元素将通过chìa khóa
而不是索引进行比较。只要chìa khóa
是唯一的,React就会移动元素而不将它们从DOM树中移除,然后将它们放回(React中称为挂载/卸载的过程)。
// ... props: { children: [ // 现在react就是根据key,而不是索引来比较了 { type: 'div', key: 'div' }, { type: 'span', key: 'span' }, { type: 'br', key: 'bt' } ] }, // ...
到目前为止,本文只触及了props
,React哲学的一部分,但忽略了state
。这是一个简单的“有状态”组件:
class App extends Component { state = { counter: 0 } increment = () => this.setState({ counter: this.state.counter + 1, }) render = () => () }
现在,上述例子中的state
对象有一个counter
属性。单击按钮会增加其值并更改按钮文本。但是当用户点击时,DOM会发生什么?它的哪一部分将被重新计算和更新?
Gọithis.setState
也会导致重新渲染,但不会导致整个页面重渲染,而只会导致组件本身及其子项。父母和兄弟姐妹都可以幸免于难。
本文准备了一个DEMO,这是修复问题前的样子。你可以在这里查看其源代码。不过在此之前,你还需要安装React Developer Tools.
打开demo要看的第一件事是哪些元素以及何时导致Virtual DOM更新。导航到浏览器的Dev Tools中的React面板,点击设置然后选择“Highlight Updates”复选框:
现在尝试在表中添加一行。如你所见,页面上的每个元素周围都会出现边框。这意味着每次添加行时,React都会计算并比较整个Virtual DOM树。现在尝试按一行内的计数器按钮。你将看到Virtual DOM如何更新 (state仅相关元素及其子元素更新)。
React DevTools暗示了问题可能出现的地方,但没有告诉开发者任何细节:特别是有问题的更新是指元素“diff”之后有不同,还是组件被unmount/mount了。要了解更多信息,开发者需要使用React的内置分析器(请注意,它不能在生产模式下工作)。
转到Chrome DevTools中的“Performance”标签。点击record按钮,然后点击表格。添加一些行,更改一些计数器,然后点击“Stop”按钮。稍等一会儿之后开发者会看到:
在结果输出中,开发者需要关注“Timing”。缩放时间轴,直到看到“React Tree Reconciliation”组及其子项。这些都是组件的名称,旁边有[update]或[mount]。可以看到有一个TableRow被mount了,其他所有的TableRow都在update,这并不是开发者想要的。
大多数性能问题都由[update]或[mount]引起
一个组件(以及组件下的所有东西)由于某种原因在每次更新时重新挂载,开发者不想让它发生(重新挂载很慢),或者在大型分支上执行代价过大的重绘,即使组件似乎没有发生任何改变。
现在,当开发者了解React如何决定更新Virtual DOM并知道幕后发生的事情时,终于准备好解决问题了!修复性能问题首先要解决 mount/unmount。
如果开发者将任何元素/组件的多个子元素在内部表示为数组,那么程序可以获得非常明显的速度提升。
考虑一下:
在虚拟DOM中,将表示为:
// ... props: { children: [ { type: Message }, { type: Table }, { type: Footer } ] } // ...
一个简单的Message
组件(是一个phân chia
带有一些文本,像是猪齿鱼的顶部通知)和一个很长的Table
,比方说1000多行。它们都是phân chia
元素的đứa trẻ
,因此它们被放置在父节点的props.children
之下,并且它们没有chìa khóa
。React甚至不会通过控制台警告来提醒开发者分配key,因为子节点React.createElement
作为参数列表而不是数组传递给父节点。
现在,用户已经关闭了顶部通知,所以Message
从树中删除。Table
,Footer
是剩下的child。
// ... props: { children: [ { type: Table }, { type: Footer } ] } // ...
React如何看待它?它将它视为一系列改变了type的child:children[0]的type本来是Message
,但现在他是Table
。因为它们都是对函数(和不同函数)的引用,它会卸载整个Table并再次安装它,渲染它的所有子代:1000多行!
因此,你可以添加唯一键(但在这种特殊情况下使用chìa khóa
不是最佳选择)或者采用更智能的trick:使用 && 的布尔短路运算,这是JavaScript
和许多其他现代语言的一个特性。像这样:
{isShowMessage && }
mặc dùMessage
被关闭了(不再显示),props.children
父母div仍将拥有三个元素,children[0]具有一个值SAI
(布尔类型)。还记得ĐÚNG VẬY
/SAI
, vô giá trị
thậm chíkhông xác định
都是Virtual DOM对象type属性的允许值吗?浏览器最终得到类似这样的东西:
// ... props: { children: [ false, // isShowMessage && 短路成了false { type: Table }, { type: Footer } ] } // ...
所以,不管Message
是否被显示,索引都不会改变,Table
仍然会和Table
比较,但仅仅比较Virtual DOM通常比删除DOM节点并从中创建它们要快得多。
现在来看看更高级的东西。开发者喜欢HOC。高阶组件是一个函数,它将一个组件作为一个参数,添加一些行为,并返回一个不同的组件(函数):
function withName(SomeComponent) { return function(props) { return ; } }
开发者在父render
方法中创建了一个HOC 。当Phản ứng
需要重新渲染树时,Phản ứng
的Virtual DOM将如下所示:
// On first render: { type: ComponentWithName, props: {}, } // On second render: { type: ComponentWithName, // Same name, but different instance props: {}, }
现在,React只会在ComponentWithName上运行一个diff算法,但是这次同名引用了一个不同的实例,三等于比较失败,必须进行完全重新挂载。注意它也会导致状态丢失,幸运的是,它很容易修复:只要返回的实例都是同一个就好了:
// 单例 const ComponentWithName = withName(Component); class App extends React.Component() { render() { return ; } }
现在浏览器已经确保不会重新装载东西了,除非必要。但是,对位于DOM树根目录附近的组件所做的任何更改都将导致其所有子项的进行对比重绘。结构复杂,价格昂贵且经常可以避免。
如果有办法告诉React不要查看某个分支,那将是很好的,因为它没有任何变化。
这种方式存在,它涉及一个叫shouldComponentUpdate
的组件生命周期函数。React会在每次调用组件之前调用此方法,并接收props
Vàstate
的新值。然后开发者可以自由地比较新值和旧值之间的区别,并决定是否应该更新组件(返回ĐÚNG VẬY
hoặcSAI
)。如果函数返回SAI
,React将不会重新渲染有问题的组件,也不会查看其子组件。
通常比较两组props
Vàstate
一个简单的浅层比较就足够了:如果顶层属性的值相同,浏览器就不必更新了。浅比较不是JavaScript
的一个特性,但开发者很多方法来自己实现它,为了不重复造轮子,也可以使用别人写好的方法.
在引入浅层比较的npm包后,开发者可以编写如下代码:
class TableRow extends React.Component { shouldComponentUpdate(nextProps, nextState) { const { props, state } = this; return !shallowequal(props, nextProps) && !shallowequal(state, nextState); } render() { /* ... */ } }
但是你甚至不必自己编写代码,因为React在一个名为React.PureComponent的类中内置了这个功能,它类似于React.Component
,只是shouldComponentUpdate
已经为你实现了浅层props/state比较。
或许你会有这样的想法,能替换Component
vìPureComponent
就去替换。但开发者如果错误地使用PureComponent
同样会有重新渲染的问题存在,需要考虑下面三种情况:
{ /* ... */ }} />
上面的代码片段演示了三种最常见的反模式,请尽量避免它们!
正确地使用PureComponent
,你可以在这里看到所有的TableRow都被“纯化”后渲染的效果。
但是,如果你迫不及待想要全部使用纯函数组件,这样是不对的。比较两组props
Vàstate
不是免费的,对于大多数基本组件来说甚至都不值得:运行shallowCompare
比diff算法需要更多时间。
可以使用此经验法则:纯组件适用于复杂的表单和表格,但它们通常会使按钮或图标等简单元素变慢。
现在,你已经熟悉了React的渲染模式,接下来就开始前端优化之旅吧。
本文由猪齿鱼技术团队原创,转载请注明出处
Vấn đề là, khi người dùng trả lời bài đăng của nhau, tôi phải làm thế này: margin-left:40px; cho 1 cấp sâu react margin-left:80px; cho 2 cấp sâu v.v. Nhưng tôi muốn div react
Tôi đang cố gắng tìm cách kết nối React Router với React VR. Đầu tiên, tôi có nên sử dụng react-router dom/native không? Hiện tại vẫn chưa rõ ràng vì React VR được xây dựng trên React.
Tôi mới làm quen với React hoặc có kiến thức cơ bản về lập trình nói chung. Tôi không chắc sự khác biệt giữa các câu lệnh import * as react from 'react' và import react from 'react' là gì. Cảm ơn bạn trước!
Tôi đang sử dụng phiên bản ổn định mới nhất của react, react-native, react-test-renderer, react-dom. Tuy nhiên, react-native phụ thuộc vào react@16.0.0-alp
Có thể phát triển ứng dụng React Native thông qua kiến trúc phần mềm như MVC, MVP, MVVM không? Cảm ơn bạn. Câu trả lời tốt nhất là có. React Native chỉ là chữ “V” trong các mẫu thiết kế phần mềm mà bạn đã đề cập. Nếu bạn xem xét nó
Xin chào, tôi đang cố gắng liên kết một hàm vào nút bên phải của trình duyệt nhưng nó lại báo lỗi. Đây là mã của tôi: import React, {Component} from 'react'; import Ico
Tôi đã tạo một ứng dụng bằng React Native và tôi đang cố gắng tạo apk. Xem http://facebook.github.io/react-native/docs/signed-apk-android.
1 [Tôi đã thử thay đổi z-index của phân trang thành 0 nhưng không được] Đây là liên kết đến codesandbox của tôi: Vui lòng kiểm tra menu thả xuống chọn cuối cùng, nó nằm sau phân trang. https://codesandbox.io/s/j
Tôi nhận thấy React có thể được nhập như thế này: import * as React from 'react'; ...hoặc như thế này: import React from 'react'; Lần nhập đầu tiên là React
Tôi mới làm quen với react-native. Tôi đang sử dụng React Native Paper để cung cấp chủ đề cho mọi màn hình. Tôi cũng đang sử dụng react-navigation stack navigator và drawer navigator. Đầu tiên, để điều hướng, chủ đề của bài viết không nằm trong thành phần điều hướng.
Tôi có một ứng dụng React Native được tạo bằng Ignite CLI. Tôi đang cố gắng sử dụng TabNavigator với React Navigation nhưng tôi không thể tìm ra cách lấy dữ liệu từ một ứng dụng
Tôi đang cố gắng thực hiện thử nghiệm chụp nhanh trong ứng dụng React của mình. Tôi hiện đang sử dụng thư viện react-testing để kiểm thử đơn vị chung. Tuy nhiên, đối với thử nghiệm chụp nhanh, tôi đã thấy nhiều cách tiếp cận khác nhau trực tuyến, sử dụng phản ứng
Tôi đang xây dựng một ứng dụng gốc đa nền tảng bằng cách sử dụng react-native và sử dụng react-navigation để điều hướng giữa các màn hình và redux để quản lý trạng thái điều hướng. Sự cố xảy ra khi tôi lồng các trình điều hướng. Ví dụ,
Tôi đang gặp phải một vấn đề khá phức tạp liên quan đến phân trang và Điều hướng React Native. Nhấp vào ngăn kéo có danh sách các danh mục và tất cả chúng sẽ chuyển đến màn hình. Phát biểu vấn đề: Khi tôi nhấp vào các danh mục một cách ngẫu nhiên, mọi thứ đều hoạt động bình thường. Tuy nhiên, tôi gặp phải sự cố trong quá trình phân trang. Giả mạo
Đây là điều hướng ngăn kéo của tôi: const DashboardStack = StackNavigator({ Dashboard: { screen: Dashboard
Đang cố gắng xây dựng ứng dụng Android react-native nhưng nhận được thông tin lỗi sau Chạy jetifier để di chuyển thư viện sang AndroidX. Bạn có thể
Hiện tại tôi đang triển khai React Router v.4 trong một ứng dụng, trong đó tôi cũng sử dụng Webpack để đóng gói. Trong cấu hình webpack của tôi, tôi có React, ReactDOM và React-route
Tôi đang sử dụng React.children để render một số tuyến con với react router (cho tất cả các tuyến con trong một tuyến chính nhất định. Điều này hoạt động tốt với tôi, nhưng trước đó tôi đã hủy cấu trúc các thuộc tính được truyền cho các tuyến con
Khi tôi chạy ứng dụng React, nó báo lỗi export 'React' (nhập dưới dạng 'React') không tìm thấy trong 'react'. Đối với tất cả các lỗi trang, hãy xem hình ảnh ở đây. Câu trả lời tốt nhất dựa trên lỗi trong hình ảnh
Tôi gặp lỗi này khi triển khai Image-slider trên ứng dụng của mình bằng ví dụ này. nhập React,{Component} từ 'react' nhập {View,T
Tôi là một lập trình viên xuất sắc, rất giỏi!