thisprops 对象的属性与组件的属性一一对应,但是有一个例外,就是 thispropschildren 属性。它表示组件的所有子节点
var NotesList = ReactcreateClass({render: function() {return (<ol>{ReactChildrenmap(thispropschildren, function (child) {return <li>{child}</li>;})}</ol>);}});ReactDOMrender(<NotesList><span>hello</span><span>world</span></NotesList>,documentbody);
上面代码的 NoteList 组件有两个 span 子节点,它们都可以通过 thispropschildren 读取,运行结果如下。
hello
world
这里需要注意, thispropschildren 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 thispropschildren 的时候要小心。
React 提供一个工具方法 ReactChildren 来处理 thispropschildren 。我们可以用 ReactChildrenmap 来遍历子节点,而不用担心 thispropschildren 的数据类型是 undefined 还是 object。
React中的useRef钩子函数提供了一个获取DOM元素的方式。通过useRef创建一个引用,我们可以将其附加到React元素上,并在需要读取或修改该元素时访问它。而ReactuseRef()会返回一个可变的 ref 对象,它的 current 属性被初始化为传入的参数(initialValue)。
如果在 useEffect 或者某个事件回调中想要获取最新挂载后的节点的话,就应该使用 ReactuseRef 并将其赋值给节点的 ref 属性,这样在事件处理程序中就可以通过 refcurrent 来访问节点。当然,如果不是必须获取最新挂载后的节点,那么直接使用 useRef 返回的 ref 对象就可以了。而 reactFromCurrent 没有找到任何相关的信息,需要更加详细的上下文来确定问题所在。
只允许返回一个父节点。
在写react组件的时候,react中组件一般都是只返回一个父节点包含的元素。
React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。由于 React的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。React主要用于构建UI,也可以传递动态变量、甚至是可交互的应用组件。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。
react 是一个数据驱动的框架,通过将数据与 UI 关联起来达到数据更新时同时更新 UI 更新的目的。对于 react web app 来说,数据的变动最终会转化为 dom 的变化。当然 react 并不会对 dom 进行直接比较,而是对比变化前的 fiber。对 fiber 的 diff 最终会反映到 dom 上。
先假设在 fiber 变化时不使用 diff 算法,即一旦 fiber 改变则删除变化前的所有 fiber 并插入变化后的 fiber 。这种方法虽然简便,但存在性能问题,因为 dom 的删除和创建都需要耗费时间。例如,fiber 从 a, b, c 变为 a, c, b。只需要将 b 插入到 c 之后即可,无需创建任何 fiber 。因此,需要一种方法来标记元素的变更,这就是 diff 算法。
如果变化后都存在多个元素,则属于多节点的 diff。多节点的 fiber diff 对于每一个 fiber 实际只存在两种情况:
为什么移动或新增 dom 都属于同一种情况,因为 react 实际上最终会调用 NodeinsertBefore() 来进行 placement *** 作,其定义如下:
因此 react 并不关心该 fiber 是移动(已经存在)还是新增(不存在需要创建)。例如 fiber 从 a, b, c, d 变为 a, c, b,d,那么 react 会将 b 这个 fiber 标记为 Placement。其余 fiber 不变。在最终进行 dom 变化时调用 parentinsertBefore(d, b) 。因此 diff 的目的并不是要 严格的找出 fiber 从哪个位置移动到哪个位置,只需要得出哪些需要删除,哪些需要 Placement 即可。
假设存在 now 以及 before 两个 fiber 集合。为了简化场景,认为 now 中的 fiber 在 before 中都存在。这时候问题可以转换为 如何移动 before 中的元素将其转换为 now 。react处理办法为 右移 before 中的部分 fiber 将其转换为 now 。例如,before 以及 after 中 key 的顺序为:
那么标记 b 为 Placement 即可。对于这个任务,我们将 上一个位置不变的元素在 now 中的位置记为 lastKeepIndex ,当遍历 now 数组中的每个 fiber 时,如果该 fiber 在 before 数组中存在,且 。则说明当前所遍历到得 fiber 在:
这就意味这这个 fiber 是需要移动的。如果不满足这个条件,则需要该 fiber 相对 lastKeepIndex 所标记的 fiber 位置没有变动,无需改变。
当然,实际上不可能 now 中的 fiber 在 before 中都能找到。但这种同样直接标记为 Placement 即可。同时在 before 中却不在 now 中的需要元素标记为 Deletion。为了方便这里我们定义 4 种类型的 Diff:
整个 diff 的逻辑为:
在得到 diff 的结果后,react 通过两个 dom *** 作函数来将 diff 应用到真实的 dom:
第一个函数对应于变化后需要进行 Placement 有兄弟节点的情况,例如 fiber 从 a,b,c,d 变化为 a,c,b,d。此时 b 被标记为 Placement。react 会找到变化后它的第一个不需要变动的兄弟节点即为 d,并调用 parentinsertBefore(d, b) 。完成后真实的 dom 就从 a,b,c,d 变成 a,c,b,d。
第二个函数对应于变化后需要进行 Placement 不存在兄弟节点的情况,例如 fiber 从 a,b,c 变化为 a,c,b 此时 b 被标记为 Placement,但其不存在兄弟节点。react 会调用 parentappendChild(b) 。完成后真实的 dom 就从 a,b,c 变成 a,c,b。
当然,真实的情况比这要更复杂。因此插入 dom 必定要先找到 fiber 树中真正的 dom 节点。而 fiber 树实际上是用户自定义组件 fiber 以及真实 dom fiber 组合在一起的,如何找到真实的兄弟 dom 节点对应的 fiber 也是一个比较复杂的任务。
react 通过 diff 算法来进行性能优化,减少 dom 的创建和删除。那么 react 采用的优化是否为 最优化 呢?答案是:否。例如存在这样一个特殊的例子:
由于 react diff 算法的局限,这里需要将 1 从 998 移动到 999 之后,但实际上我们一眼就能看出最简单的方法是将 999 移动到 1 之前。这也就是最近很多框架开始使用 最长上升子序列 来优化 diff 算法的原因。那么问题来了,你知道为什么这里 react 需要移动 998 个元素,或者说为什么最长上升子序列可以解决整个问题吗
还是直接上原话吧
A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES
翻译成人话,react是用来构建前端界面的,稍微专业一点,澄清一个可能被大家误解的概念,react不是mvc框架,
而是构建mvc里面view这部分的库,至于其他部分采用什么技术react并不限制。
一句话,react就是构建用户界面的。
1因为它火,学它能找好工作涨工资
2那么为啥它火?因为他牛逼,为啥牛逼,我们下面就说。
既然说了它牛逼,那么我们就从三个部分去说说。
涉及到简单的基础知识,比如安装,配置,基础知识和简要的小例子
实际上线react应该如何做,比如使用可以构建版本的react,模块化,和压缩等。
我们研究下看看react如何实习它说的用js写原生应用。
官网: >
一、众多周知可以forwardRef可以转发ref属性
比如要在父组件中调用子组件中某个DOM节点或者组件的ref
二、除开传递ref值,还可以巧妙的传递自己想要的值,例如调用三方组件,三方组件接受一个自定义组件,想要在自定义组件获取额外的props。比如num,以下这种方式就不好处理。
当然你也可以用redux,但是仅仅为了取一个值就用redux开销有点大, 这儿我们就可以巧妙的使用ReactforwardRef,修改Father组件
这样在Content组件中既可以获取Child组件中flag也可以获取Father组件中传递的num
最后的结果
所有的html,css都可以写在js中,这就是jsx的用法。
用于验证数据的类型是否是满足你的需要,不过我在现有的项目中没有特意的指定数据的propTyoe,因为这些都是前后端约定好的。
此用法如下图 :
这个如同vue组件里面的props中的type:Array这个一样
这个与vue-router差不多,大家可以看文档。
react-router的中文官网 : 中文官网
因为react与vue一样,都是使用vitural-dom,没有处理dom节点,从而大大提高了页面的渲染效率。
当你想要获取真实的dom节点的时候,可以使用ref,具体的使用,可以看阮一峰的react入门,我下面的todolist的demo里面也会涉及到。
不过在你使用无状态组件申明组件的时候,ref在这个组件中是不能使用的。
可以通过webpack安装各种依赖,我使用的最爽的一个就是react-hot-loader,就是热更新,非常好用。不过热更新其他的工具,比如 browser-sync ,下面是一些文档。
如vue的vue-cli脚手架, create-react-app ]( >
一、选取 DOM 元素
在 jQuery 中,我们已经熟悉了使用 sizzle 选择器来完成 DOM 元素的选取。而在 React 中,我们可以使用 ref 来更有针对性的获取元素。
import React from 'react';class Demo extends ReactCompoent {
getDomNode() { return thisrefsroot; // 获取 Dom Node }
render() { return ( <div ref="root">just a
demo</div> ); }}
这是最简单的获取 node 的方式,如果有多层结构嵌套呢?没有关系。
import React from 'react';class Demo extends ReactCompoent {
getRootNode() { return thisrefsroot; // 获取根节点 Dom Node }
getLeafNode() { return thisrefsleaf; // 获取叶节点 Dom Node }
render() { return ( <div ref="root">
<div ref="leaf">just a demo</div>
</div> ); }}
如果是组件和组件嵌套呢?也没关系,父组件仍然可以拿到子组件的根节点。
import React from 'react';import ReactDOM from 'react-dom';class Sub
extends ReactCompoent { render() { return (
<div>a sub component</div> ); }}class Demo extends
ReactCompoent { getDomNode() { return thisrefsroot; // 获取
Dom Node } getSubNode() { return
ReactDOMfindDOMNode(thisrefssub); // 获取子组件根节点 } render() {
return ( <div ref="root"> <Sub
ref="sub" /> </div> ); }}
上面使用了比较易懂的 API 来解释 Ref 的用法,但里面包含了一些现在 React 不太推荐和即将废弃的方法,如果用 React 推荐的写法,我们可以这样写。
import React from 'react';import ReactDOM from 'react-dom';class Sub
extends ReactCompoent { getDomNode() { return thisrootNode;
} render() { return ( <div ref={(c) =>
thisrootNode = c}>a sub component</div> ); }}class
Demo extends ReactCompoent { getDomNode() { return
thisrootNode; // 获取 Dom Node } getSubNode() { return
thissubgetDomNode(); // 获取子组件根节点 } render() { return (
<div ref={(c) => thisrootNode = c}>
<Sub ref={(c) => thissub = c} /> </div>
); }}
有人可能会问,那子组件怎么拿父组件的 Dom Node 呢,从 React
的单向数据流角度出发,遇到这种情况我们应该通过回调通知给父组件,再由父组件自行判断如何修改 Node,其实父组件拿子组件的 Node
情况也很少,大多数情况下我们是通过 props 传递变化给子组件,获取子组件
Node,更多的情况下是为了避开大量重新渲染去修改一些Node的属性(比如 scrollLeft)。
二、DOM *** 作
jQuery 中提供了丰富的 *** 作方法,但一个个 *** 作 DOM 元素有的时候真的很烦人并且容易出错。React 通过数据驱动的思想,通过改变 view 对应的数据,轻松实现 DOM 的增删 *** 作。
class Demo extends ReactCompoent { constructor(props) {
super(props); thisstate = { list: [1, 2, 3],
}; thisaddItemFromBottom = thisaddItemFromBottombind(this);
thisaddItemFromTop = thisaddItemFromTopbind(this);
thisdeleteItem = thisdeleteItembind(this); }
addItemFromBottom() { thissetState({ list:
thisstatelistconcat([4]), }); } addItemFromTop() {
thissetState({ list: [0]concat(thisstatelist),
}); } deleteItem() { const newList =
[thisstatelist]; newListpop(); thissetState({
list: newList, }); } render() { return (
<div> {thisstatelistmap((item) =>
<div>{item}</div>)} <button
onClick={thisaddItemFromBottom}>尾部插入 Dom 元素</button>
<button onClick={thisaddItemFromTop}>头部插入 Dom
元素</button> <button
onClick={thisdeleteItem}>删除 Dom 元素</button>
</div> ); }} 三、事件的监听
React 通过根节点代理的方式,实现了一套很优雅的事件监听方案,在组件 unmount 时也不需要自己去处理内存回收相关的问题,非常的方便。
import React from 'react';class Demo extends ReactComponent {
constructor(props) { super(props); thishandleClick =
thishandleClickbind(this); } handleClick() {
alert('我是d窗'); } render() { return ( <div
onClick={thishandleClick}>点击我d出d框</div> ); }}
这里有一个小细节就是
bind 的时机,bind 是为了保持相应函数的上下文,虽然也可以在 onClick 那里 bind,但这里选择在 constructor 里
bind 是因为前者会在每次 render 的时候都进行一次 bind,返回一个新函数,是比较消耗性能的做法。
但
React 的事件监听,毕竟只能监听至 root component,而我们在很多时候要去监听 window/document 上的事件,如果
resize、scroll,还有一些 React 处理不好的事件,比如
scroll,这些都需要我们自己来解决。事件监听为了屏蔽差异性需要做很多的工作,这里像大家推荐一个第三方库来完成这部分的工作,
add-dom-event-listener ,用法和原生的稍有区别,是因为这个库并不旨在做 polyfill,但用法还是很简单。
var addEventListener = require('add-dom-event-listener');var handler =
addEventListener(documentbody, 'click', function(e){
consolelog(etarget); // works for ie consolelog(enativeEvent); //
native dom event});handlerremove(); // detach event listener
另一个选择是 bean ,达到了 IE6+ 级别的兼容性。
四、事件的触发
和事件监听一样,无论是 Dom 事件还是自定义事件,都有很优秀的第三方库帮我们去处理,如果是 DOM 事件,推荐 bean ,如果是自定义事件的话,推荐 PubSubJS 。
五、documentready
React
作为一个 view 层框架,通常情况下页面只有一个用于渲染 React 页面组件的根节点 div,因此
documentready,只需把脚本放在这个 div 后面执行即可。而对于渲染完成后的回调,我们可以使用 React 提供的
componentDidMount 生命周期。
import React from 'react';class Demo
extends ReactComponent { constructor(props) { super(props);
} componentDidMount() { doSomethingAfterRender(); //
在组件渲染完成后执行一些 *** 作,如远程获取数据,检测 DOM 变化等。 } render() { return (
<div>just a demo</div> ); }} 六、attr 方法
jQuery 使用 attr 方法,获取 Dom 元素的属性。在 React 中也可以配合 Ref 直接读取 DOM 元素的属性。
import React from 'react';class Demo extends ReactComponent {
constructor(props) { super(props); }
componentDidMount() { thisrootNodescrollLeft = 10; //
渲染后将外层的滚动调至 10px } render() { return ( <div
ref={(c) => thisrootNode = c}
style={{ width: '100px', overflow: 'auto' }} >
<div style={{ width: '1000px' }}>just a demo</div>
</div> ); }}
但是,在大部分的情况下,我们完全不需要做,因为 React 的单向数据流和数据驱动渲染,我们可以不通过 DOM,轻松拿到和修改大部分我们需要的 DOM 属性。
import React from 'react';class Demo extends ReactComponent {
constructor(props) { super(props); thisstate = {
link: '//>
以上就是关于react 获取this.props.children 的对象实例全部的内容,包括:react 获取this.props.children 的对象实例、reactfromcurrent里面没有东西、react14如何返回两个节点等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)