map使用 react.js_react 去除打包后的js.map - CSDN
  • 文章目录React.map源码阅读React.jsReactChildren.jsmapChildren()mapIntoWithKeyPrefixInternal()getPooledTraverseContext()getPooledTraverseContext()对象池traverseAllChildren()releaseTraverseContext()...

    React.Children.map

    先来看这样一段代码:

    import React from 'react';
    function Father(props){
        console.log(props.children);
        console.log(React.Children.map(props.children, item=>[item, item]));
        return props.children;
    }
    
    export default () => (
        <Father>
            <div>hello</div>
            <div>hello</div>
            <div>hello</div>
        </Father>
    );
    

    代码很简单,在页面上只是显示了三行"hello"而已。重点不在这里,而是在于通过console.log在控制台输出的内容。

    我们知道可以通过组件的props.children获得该组件的子组件。那么可以想到console.log(props.children);预期的结果应该是打印出一个长度为3的数组。

    在这里插入图片描述
    事实也确实如此,控制台中输出了一个长度为3的ReactElement数组。

    那么console.log(React.Children.map(props.children, item=>[item, item]));会在控制台输出什么呢?

    我们可能会猜想它应该与数组的map方法一样,返回一个长度为3的二维数组,每个元素又是一个长度为2的ReactElement数组。

    [外链图片转存失败(img-TllfUeS0-1566355435380)(https://note.youdao.com/src/56F110D12C694C76B14B90D5E062FE0D)]

    可事实却并不是这样,控制台输出的是一个长度为6的ReactElement数组。可以想见,React.map将我们设想中的二维数组给降维了。

    具体过程是怎样,需要看看源码。

    源码阅读

    React.js

    首先在源码目录下的React.js可以发现map是在此处成为React.Children的一个方法的。

    在这里插入图片描述

    接着可以发现它真正的定义是在同目录下的ReactChildren.js文件中。
    在这里插入图片描述

    ReactChildren.js

    ReactChildren.js文件的最尾部,可以看到map方法在此处被导出,其真正的名字应该是mapChildren
    在这里插入图片描述

    mapChildren()

    function mapChildren(children, func, context) {
      if (children == null) {
        return children;
      }
      const result = [];
      mapIntoWithKeyPrefixInternal(children, result, null, func, context);
      return result;
    }
    

    这个方法接受3个参数childrenfunccontext

    children就是将要被遍历的子组件数组,func是对单个子组件需要执行的函数,context则是func执行时this指针所指向的对象。

    mapIntoWithKeyPrefixInternal()

    function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
      let escapedPrefix = '';
      if (prefix != null) {
        escapedPrefix = escapeUserProvidedKey(prefix) + '/';
      }
      const traverseContext = getPooledTraverseContext(
        array,
        escapedPrefix,
        func,
        context,
      );
      traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
      releaseTraverseContext(traverseContext);
    }
    

    这个方法本身并没有什么可说的,值得说的是其中被调用的getPooledTraverseContexttraverseAllChildrenreleaseTraverseContext

    getPooledTraverseContext()

    getPooledTraverseContext()

    const POOL_SIZE = 10;
    const traverseContextPool = [];
    
    function getPooledTraverseContext(
      mapResult,
      keyPrefix,
      mapFunction,
      mapContext,
    ) {
      if (traverseContextPool.length) {
        const traverseContext = traverseContextPool.pop();
        traverseContext.result = mapResult;
        traverseContext.keyPrefix = keyPrefix;
        traverseContext.func = mapFunction;
        traverseContext.context = mapContext;
        traverseContext.count = 0;
        return traverseContext;
      } else {
        return {
          result: mapResult,
          keyPrefix: keyPrefix,
          func: mapFunction,
          context: mapContext,
          count: 0,
        };
      }
    }
    

    traverseContextPool是文件中定义的对象池,POOL_SIZE则定义了对象池的大小。

    getPooledTraverseContext方法就是从对象池中获得一个context对象。

    逻辑是若对象池已存在对象则pop出来,并将我们调用React.map时传入的一些参数赋值给context对象中相应的属性。

    若对象池为空,则直接返回一个新的context对象。

    对象池

    对象池的作用是避免频繁的创建和销毁,以避免不必要的性能消耗和内存抖动的问题。

    traverseAllChildren()

    function traverseAllChildren(children, callback, traverseContext) {
      if (children == null) {
        return 0;
      }
    
      return traverseAllChildrenImpl(children, '', callback, traverseContext);
    }
    

    这个方法用以判断传入的子组件是否为空,不是空的再继续调用traverseAllChildrenImpl方法。
    值得注意的是,参数中的callback并不是我们传入的回调函数,而是之前在mapIntoWithKeyPrefixInternal中传入的mapSingleChildIntoContext

    releaseTraverseContext()

    function releaseTraverseContext(traverseContext) {
      traverseContext.result = null;
      traverseContext.keyPrefix = null;
      traverseContext.func = null;
      traverseContext.context = null;
      traverseContext.count = 0;
      if (traverseContextPool.length < POOL_SIZE) {
        traverseContextPool.push(traverseContext);
      }
    }
    

    在前面通过getPooledTraverseContext获得到的context对象在使用过后,会通过这个方法将对象内属性清空并重新放入对象池中(当对象池还有空间时)。

    看到这里可能大家会有一个疑问。最开始的时候对象池为空,于是直接返回了一个新的context对象,使用完之后,通过
    releaseTraverseContext方法放回对象池中。而在又一次从对象池中获取对象的过程中,获得到的正是我们刚刚放进去的那一个,那么岂不是对象池中始终只有一个对象?我们接着往下看。

    traverseAllChildrenImpl()

    function traverseAllChildrenImpl(
      children,
      nameSoFar,
      callback,
      traverseContext,
    ) {
      const type = typeof children;
    
      if (type === 'undefined' || type === 'boolean') {
        // All of the above are perceived as null.
        children = null;
      }
    
      let invokeCallback = false;
    
      if (children === null) {
        invokeCallback = true;
      } else {
        switch (type) {
          case 'string':
          case 'number':
            invokeCallback = true;
            break;
          case 'object':
            switch (children.$$typeof) {
              case REACT_ELEMENT_TYPE:
              case REACT_PORTAL_TYPE:
                invokeCallback = true;
            }
        }
      }
    
      if (invokeCallback) {
        callback(
          traverseContext,
          children,
          // If it's the only child, treat the name as if it was wrapped in an array
          // so that it's consistent if the number of children grows.
          nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,
        );
        return 1;
      }
    
      let child;
      let nextName;
      let subtreeCount = 0; // Count of children found in the current subtree.
      const nextNamePrefix =
        nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;
    
      if (Array.isArray(children)) {
        for (let i = 0; i < children.length; i++) {
          child = children[i];
          nextName = nextNamePrefix + getComponentKey(child, i);
          subtreeCount += traverseAllChildrenImpl(
            child,
            nextName,
            callback,
            traverseContext,
          );
        }
      } else {
        const iteratorFn = getIteratorFn(children);
        if (typeof iteratorFn === 'function') {
          if (__DEV__) {
            // Warn about using Maps as children
            if (iteratorFn === children.entries) {
              warning(
                didWarnAboutMaps,
                'Using Maps as children is unsupported and will likely yield ' +
                  'unexpected results. Convert it to a sequence/iterable of keyed ' +
                  'ReactElements instead.',
              );
              didWarnAboutMaps = true;
            }
          }
    
          const iterator = iteratorFn.call(children);
          let step;
          let ii = 0;
          while (!(step = iterator.next()).done) {
            child = step.value;
            nextName = nextNamePrefix + getComponentKey(child, ii++);
            subtreeCount += traverseAllChildrenImpl(
              child,
              nextName,
              callback,
              traverseContext,
            );
          }
        } else if (type === 'object') {
          let addendum = '';
          if (__DEV__) {
            addendum =
              ' If you meant to render a collection of children, use an array ' +
              'instead.' +
              ReactDebugCurrentFrame.getStackAddendum();
          }
          const childrenString = '' + children;
          invariant(
            false,
            'Objects are not valid as a React child (found: %s).%s',
            childrenString === '[object Object]'
              ? 'object with keys {' + Object.keys(children).join(', ') + '}'
              : childrenString,
            addendum,
          );
        }
      }
    
      return subtreeCount;
    }
    

    这部分代码算得上是React.map实现的核心之一,我们逐段逐段的看。

    const type = typeof children;
    
      if (type === 'undefined' || type === 'boolean') {
        // All of the above are perceived as null.
        children = null;
      }
    
      let invokeCallback = false;
    
      if (children === null) {
        invokeCallback = true;
      } else {
        switch (type) {
          case 'string':
          case 'number':
            invokeCallback = true;
            break;
          case 'object':
            switch (children.$$typeof) {
              case REACT_ELEMENT_TYPE:
              case REACT_PORTAL_TYPE:
                invokeCallback = true;
            }
        }
      }
    

    这段代码是用来判断传入的子组件的,主要是判断是不是单个对象以及类型。如果满足条件,则将invokeCallback置为true


    if (invokeCallback) {
        callback(
          traverseContext,
          children,
          // If it's the only child, treat the name as if it was wrapped in an array
          // so that it's consistent if the number of children grows.
          nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,
        );
        return 1;
      }
    

    若上面的代码将invokeCallback置为true,则调用callback,注意此处的callback不是我们传入的回调函数,而是mapSingleChildIntoContext


    if (Array.isArray(children)) {
        for (let i = 0; i < children.length; i++) {
          child = children[i];
          nextName = nextNamePrefix + getComponentKey(child, i);
          subtreeCount += traverseAllChildrenImpl(
            child,
            nextName,
            callback,
            traverseContext,
          );
        }
      }
    

    这段代码则是用以处理传入的是数组的情况的。若为数组,则会遍历数组,并将数组中的每一个元素作为traverseAllChildrenImpl的第一个参数,递归的调用自身。

    mapSingleChildIntoContext

    这个方法是React.map实现的另一个核心。

    function mapSingleChildIntoContext(bookKeeping, child, childKey) {
      const {result, keyPrefix, func, context} = bookKeeping;
    
      let mappedChild = func.call(context, child, bookKeeping.count++);
      if (Array.isArray(mappedChild)) {
        mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c);
      } else if (mappedChild != null) {
        if (isValidElement(mappedChild)) {
          mappedChild = cloneAndReplaceKey(
            mappedChild,
            // Keep both the (mapped) and old keys if they differ, just as
            // traverseAllChildren used to do for objects as children
            keyPrefix +
              (mappedChild.key && (!child || child.key !== mappedChild.key)
                ? escapeUserProvidedKey(mappedChild.key) + '/'
                : '') +
              childKey,
          );
        }
        result.push(mappedChild);
      }
    }
    

    在这个方法里,我们从context对象中获取到调用React.map时传入的回调函数,并执行。

    下面这段代码解释了一开始的问题,为什么我们调用React.map,尽管预期是一个二维数组,而返回的却是一个一维数组。

    if (Array.isArray(mappedChild)) {
        mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c);
    }
    

    如果执行我们传入的回调函数后返回的是一个数组,那么则会将这个数组作为参数,重新走一遍调用React.map之后的流程,且此时传入的回调函数就只返回本身。

    同时这段代码还解释了,对象池是不是一直只有一个对象的问题。

    在当我们传入的回调函数不返回一个数组时确实是这样的,但当返回一个数组,甚至是多维数组时,在此处由于会多次重走流程,于是也会多次向对象池获取对象,然而第一次获取到的对象此时还未被放回对象池中。于是便会直接返回一个新的对象,当整个方法调用完成后,对象池中便会存在多个对象了。

    流程图

    在这里插入图片描述

    展开全文
  • 1、由于在props中写明children时一个React.ReactNode类型(此类型代表children可以是任何类型),所以即使类型检查为array类型,在使用children.map()的时候认为children依旧时全类型,不包含map方法。 2、这...

    问题:在使用children过程中发现children不包含map方法,但是类型验证表明children就是array类型

    解决:

    1、由于在props中写明children时一个React.ReactNode类型(此类型代表children可以是任何类型),所以即使类型检查为array类型,在使用children.map()的时候认为children依旧时全类型,不包含map方法。

    2、这里使用React.Children.map将children转化为固定array类型,也就包含了map方法。

    案例:

    父组件使用:

    children?: React.ReactNode;
    render(){
            const { children} = this.props;
            return React.Children.map(children, (child: any, index) => {
                console.log(child)
                return (
                  <div>
                    {child}
                  </div>
                );
              });  
        }

     

    展开全文
  • React.js踩坑中...

    2016-10-12 16:40:41
    公司新项目暂定技术使用React.js,先找几个DEMO试试,其中语法与之前的语法有点点的区别,最坑爹的是没有一个完美的IDE,作为脑子懒得人,没有快捷联想,我的天~~~废话不多说直接上。。。 IDE:Sublime Text 3,更新...

    公司新项目暂定技术使用React.js,先找几个DEMO试试,其中语法与之前的语法有点点的区别,最坑爹的是没有一个完美的IDE,作为脑子懒得人,没有快捷联想,我的天~~~废话不多说直接上。。。

    IDE:Sublime Text 3,更新ReactJS插件,勉强使用。

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8" />
    		<title>Hello React!</title>
    		<script src="js/react.min.js"></script>
    		<script src="js/react-dom.min.js"></script>
    		<script src="js/browser.min.js"></script>
    		<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
    	</head>
    
    	<body>
    		<p>-----------------按鈕点击--------------------------------</p>
    		<div id="content"></div>
    		<p>-----------------数组解析/组件嵌套--------------------------------</p>
    		<div id="arraycontent"></div>
    		<p>-----------------获取真实的DOM节点--------------------------------</p>
    		<div id="getDOM"></div>
    		<p>-----------------获取jsx--------------------------------</p>
    		<div id="getJSX"></div>
    		<p>///----------------------提交表单----------------------------</p>
    		<div id="submitForm"></div>
    		<script type="text/babel" src="content.js" ></script>
    	</body>
    
    </html>
    js

    //-----------------按鈕点击--------------------------------
    var Clickapp=React.createClass({
    	getInitialState:function () {
    		// body...
    		return { clickCount:0,};
    	},
    	handleClick:function () {
    		// body...
    		this.setState({
    			clickCount:this.state.clickCount+1,
    		});
    	},
    	render:function () {
    		// body...
    		return(<div>
    				<h2>点击下面按钮</h2>
    				<button onClick={this.handleClick}>点击我</button>
    				<p>一共点击了:{this.state.clickCount}</p>	
    			</div>);
    	}
    });
    
    ReactDOM.render(<Clickapp /> ,document.getElementById('content')); 
    
    //<p>-----------------数组解析/组件嵌套--------------------------------</p>
     
    var data = [
      {id: 1, author: "Pete Hunt", text: "This is one comment"},
      {id: 2, author: "Jordan Walke", text: "This is *another* comment"}
    ];
     var ArrayText=React.createClass({
     	rawMarkup: function() {
        		var md = new Remarkable();
        		var rawMarkup = md.render(this.props.comment);
        		return { __html: rawMarkup };
      		},
    	  handleAuthorOnClick: function() {
    	   	alert(e.target.value);
    	  },
     	render() {
     		return (
     			<div>
     				<h1 onClick={this.handleAuthorOnClick}>{this.props.author}</h1>
     				<span dangerouslySetInnerHTML={this.rawMarkup()}></span>
     			</div>
     		);
     	}
     });
    var Arraycontent=React.createClass({
     	render() {
     		var ArrayNodes = this.props.data.map(function(comment) {
          		return (<div><ArrayText author={comment.author} comment={comment.text}/></div>);
          		}
          	);
     		return (<div>{ArrayNodes}</div>);
     	}
     });
    ReactDOM.render(<Arraycontent data={data} /> ,document.getElementById('arraycontent')); 
    
    ///<p>-----------------获取真实的DOM节点--------------------------------</p>
    
    var GetDOM=React.createClass({
    	getInitialState:function () {
    		// body...
    		return {inputText:"未选中",isCheck:false};
    	},
    	handleClick:function () {
    		this.setState({
    			isCheck:this.state.isCheck?false:true,
    			inputText:!this.state.isCheck?"已选中":"未选中"
    		});
    	},
    	render(){
    		return(
    				<div>	
    					<input type="checkbox" checked={this.state.isCheck}></input>{this.state.inputText}
    
    					<input type="button" value="改变选中状态" onClick={this.handleClick}></input>
    				</div>
    			);
    	}
    });
    ReactDOM.render(<GetDOM /> ,document.getElementById('getDOM')); 
    
    ///----------------------提交表单----------------------------
    var Checkbox=React.createClass({
    	render(){
    		return (<div>
    					<input onChange={this.props.handleCheckboxChange}  type="checkbox" value="A">A</input>
    					<input onChange={this.props.handleCheckboxChange} type="checkbox" value="B">B</input>
    					<input onChange={this.props.handleCheckboxChange} type="checkbox" value="C">C</input>
    			</div>)
    	}
    });
    var Radio=React.createClass({
    	render(){
    		return (<div>
    					<input onChange={this.props.handleRadioChange} type="radio" name="radio" value="A">A</input>
    					<input onChange={this.props.handleRadioChange} type="radio" name="radio" defaultChecked value="B">B</input>
    					<input onChange={this.props.handleRadioChange} type="radio" name="radio" value="C">C</input>
    				</div>)
    	}
    });
    var SubmitForm=React.createClass({
    	getInitialState:function(){
    		return {
    			textValue:"input value",
    			selectValue:"B",
    			checkboxValue:[],
    			textareaValue:"input same ....",
    			radioValue:"C",
    		}
    	},
    	handleRadioChange:function(e){
    		this.setState({
    			radioValue:e.target.value,
    		});
    	},
    	handleCheckboxChange:function(e){
    		var checkboxArr=this.state.checkboxValue.slice();
    		var newVal=e.target.value;
    		var index=checkboxArr.indexOf(newVal);
    		if(index==-1){
    			checkboxArr.push(newVal)
    		}else{
    			checkboxArr.splice(index,1)
    		}
    		this.setState({
    			checkboxValue:checkboxArr,
    		});
    	},
    	handleSubmit:function(e){
    		e.preventDefault();
    		var formData={
    			textValue:this.refs.inputText.getDOMNode().value,
    			selectValue:this.refs.inputSelect.getDOMNode().value,
    			radioValue:this.state.radioValue,
    			checkboxValue:this.state.checkboxValue
    		}
    		console.log('the form result is:')
    		console.log(formData)
    		 
    	},
    	render(){
    		return (
    			<form onSubmit={this.handleSubmit}>
    				文本:<input type="text" ref="inputText" defaultValue={this.state.textValue} />
    				<br/>
    				<br/>
    				选项:<select defaultValue={this.state.selectValue} ref="inputSelect">
    					<option value="A">A</option>
    					<option value="B">B</option>
    					<option value="C">C</option>
    					<option value="D">D</option>
    				</select>
    				<br/>
    				<br/>
    				单选:
    				<Radio handleRadioChange={this.handleRadioChange}/>
    				<br/>
    				多选:
    				<Checkbox handleCheckboxChange={this.handleCheckboxChange}/>
    				<br/>
    				<input type="submit"></input>
    			</form>
    			);
    	}
    });
    ReactDOM.render(<SubmitForm /> ,document.getElementById('submitForm')); 
    

    实现最后一个提交表单的功能时,虽然把值获取出来,但是在给checkBox,radioBox 赋默认值时,不知如何下手,慢慢来~~明日j继续..

    ///------------------------获取网络数据----------------------------------
    var UserGist=React.createClass({
        getInitialState:function(){
            return{
                    username: '',
                    lastGistUrl: ''
            };
        },
        componentDidMount:function(){
            $.get(this.props.source,function(result){
                var lastGist=result[0];
                if(this.isMounted()){
                    this.setState({
                        username:lastGist.owner.login,
                        lastGistUrl:lastGist.html_url
                    });
                }
            }.bind(this))
        },
        render:function(){
            return(
                <div>
                     {this.state.username}'s last gist is <a href={this.state.lastGistUrl}>here</a>.
                </div> 
            );
        }
    });
    //<p>----------获取网络数据2----------</p>  
    var RepoList=React.createClass({
        getInitialState:function(){
            return{
                loading: true,
                error: null,
                data: null
            }
        },
        //then()方法是异步执行 就是当.then()前的方法执行完后再执行then()内部的程序 这样就避免了,数据没获取到等的问题
          componentDidMount:function() {
            this.props.promise.then(
              (value) => this.setState({loading: false, data: value}))
          },
    
        render:function(){
            if (this.state.loading) {
                return <span>Loading...</span>;
            }else if (this.state.error !== null) {
                return <span>Error: {this.state.error.message}</span>;
            }else {
                console.log(data)
                var repos = this.state.data.items;
                var repoList = repos.map(function (repo, index) {
                return (
                   <Form> <li key={index}><a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description}</li></Form>
                    );
                });
                return (
                    <main>
                      <h1>Most Popular JavaScript Projects in Github</h1>
                      <ol>{repoList}</ol>
                    </main>
                  )
            }
        }
    });


    因为项目UI为weui,故加入

    import React from 'react';
    import ReactDOM from 'react-dom';
    import $ from 'jquery'
    import {ButtonArea,
        Button,
        Cells,
        CellsTitle,
        CellsTips,
        Cell,
        CellHeader,
        CellBody,
        CellFooter,
        Form,
        FormCell,
        Icon,
        Input,
        Label,
        TextArea,
        Switch,
        Radio,
        Checkbox,
        Select,
        Uploader} from 'react-weui';
    import Page from '../../component/page';

    比较乱...


    展开全文
  • 使用React.Children.map()函数   const App = (props) =&gt; { return ( &lt;ul&gt; {a.map(i =&gt; { return &lt;li key={i}&gt;{i}&lt;/li&gt; })} &lt;/ul&gt...

     

     

    使用React.Children.map()函数

     

    const App = (props) => {
      return (
        <ul>
          {a.map(i => {
            return <li key={i}>{i}</li>
          })}
        </ul>
      )
    }

    使用下方写法,效果与上放写法效果相同,写法简单

    const App = (props) => {
      return (
        <ul>
          {React.Children.map(a, i => <li>{i}</li>)}
        </ul>
      )
    }

    React.Children我们可用的对象中还有其他几种非常有用的方法。我们将主要使用该React.Children.map()功能,但了解其他可用的功能是很好的。查看文档以获取更长的列表。

     

    这篇文章是30天React系列的一部分 。

    在本系列中,我们将从非常基础开始,逐步了解您需要了解的所有内容,以便开始使用React。如果您曾经想学习React,那么这里就是您的最佳选择!

    下载免费的PDF

    30天的React Mini-Ebook

    重复元素

    在Github上编辑此页面

    今天我们将研究如何显示多个组件,以准备将外部数据导入我们的应用程序。

    到目前为止,我们一直在构建一个没有任何外部数据的基本应用程序。在我们到达那里之前(明天我们将开始使用此功能),让我们看一下前两周我们掩盖的内容:

    重复元素

    在我们迭代一个对象列表并在屏幕上渲染多个组件之前,我们已经看到了这一点。在我们通过加载外部数据在我们的应用程序中添加太多复杂性之前,今天我们将快速查看如何在我们的应用程序中重复组件/元素。

    由于JSX被浏览器视为普通JavaScript,因此我们可以在JSX中使用模板标签内的任何ole'JavaScript。我们已经看到了这一点。作为快速演示:

    const a = [10,100];
    const App = (props) => {
      return (
        <ul>
          {a.map(i => {
            return <li>{i}</li>
          })}
        </ul>
      )
    }

    请注意,模板标签内部的内容{}看起来就像简单的JavaScript。那是因为它只是JavaScript。此功能允许我们在模板标记内部使用(大多数)JavaScript的本机功能,包括本机迭代器,例如mapforEach

    让我们看看我们在这里的含义。让我们将前一个示例的a值从单个整数转换为整数列表:

    const a = [1, 10, 100, 1000, 10000];

    我们可以a在组件内部映射变量,并返回将为我们构建虚拟DOM的React组件列表。

    const App = (props) => {
      return (
        <ul>
          {a.map(i => {
            return <li>{i}</li>
          })}
        </ul>
      )
    }

    功能是什么map()

    map函数是数组上的本机JavaScript内置函数。它接受一个在数组的每个元素上运行的函数,因此上面的函数将以istart为值运行四次1,然后它将再次运行它为第二个值i设置为as 10等等等等向前。

    让我们在App这里使用我们的组件更新我们在第12天创建的应用程序。让我们打开我们的src/App.js文件,App用这个源代替组件的内容。清理一些未使用的变量,你src/App.js应该看起来像这样:

    import React from 'react';
    
    const a = [1, 10, 100, 1000, 10000];
    const App = (props) => {
      return (
        <ul>
          {a.map(i => {
            return <li>{i}</li>
          })}
        </ul>
      )
    }
    
    export default App

    使用命令生成的create-react-app命令再次启动应用程序:npm start,我们可以看到应用程序正在浏览器中运行!

    但是,如果我们打开开发者控制台,我们会看到打印出错误。这个错误是由于React不知道如何跟踪列表中的各个组件这一事实,因为每个<li />组件看起来都像一个组件。

    出于性能原因,React使用虚拟DOM来尝试限制重新呈现视图时需要更新的DOM元素的数量。也就是说,如果没有任何改变,React将不会让浏览器更新任何东西以节省工作。

    此功能对于构建Web应用程序非常有用,但有时我们必须通过为节点提供唯一标识符来帮助React。映射列表并在地图中渲染组件就是其中之一。

    React希望我们通过使用特殊的prop 来唯一地标识组件:key列表中每个元素的prop。该key道具可以是任何东西,我们想要的,但它必须是唯一的该元素。在我们的示例中,我们可以i在映射中使用该变量,因为数组中没有其他元素具有相同的值。

    让我们更新我们的映射来设置密钥:

    const App = (props) => {
      return (
        <ul>
          {a.map(i => {
            return <li key={i}>{i}</li>
          })}
        </ul>
      )
    }

    孩子

    我们本周早些时候讨论了建立亲子关系的问题,但让我们更详细地了解一下我们如何访问父组件内的子项以及如何呈现它们。

    在第11天,我们构建了一个<Formatter />组件来处理Clock组件中的日期格式,以便为用户提供自定义时钟渲染的灵活性。回想一下,我们创建的实现实际上非常丑陋且相对复杂。

    const Formatter = (props) => {
      let children = props.format.split('').map((e, idx) => {
        if (e === 'h') {
          return <Hour key={idx} {...props} />
        } else if (e === 'm') {
          return <Minute key={idx} {...props} />
        } else if (e === 's') {
          return <Second key={idx} {...props} />
        } else if (e === 'p') {
          return <Ampm key={idx} {...props} />
        } else if (e === ' ') {
          return <span key={idx}> </span>;
        } else {
          return <Separator key={idx} {...props} />
        }
      });
    
      return <span>{children}</span>;
    }

    我们可以使用该React.Children对象映射React对象列表,并让React做这个繁重的工作。结果是一个更清洁的Formatter组件(不完美,但功能):

    const Formatter = ({format, state}) => {
      let children = format.split('').map(e => {
        if (e == 'h') {
          return <Hour />
        } else if (e == 'm') {
          return <Minute />
        } else if (e == 's') {
          return <Second />
        } else if (e == 'p') {
          return <Ampm />
        } else if (e == ' ') {
          return <span> </span>;
        } else {
          return <Separator />
        }
      });
      return (<span>
          {React.Children
            .map(children, c => React.cloneElement(c, state))}
          </span>)
    }

    React.cloneElement

    我们还没有讨论这个React.cloneElement()功能,所以我们在这里简要介绍一下。记得WWWWWAAAAAYYYYY回到第2天我们看了浏览器如何看待 JSX?它将其转换为类似于以下内容的JavaScript:

    React.createElement("div", null, 
     React.createElement("img", {src: "profile.jpg", alt: "Profile photo"}),
     React.createElement("h1", null, "Welcome back Ari")
    );

    我们不是创建一个新的组件实例(如果我们已经有一个),有时我们会想要复制它或将自定义道具/子项添加到组件中,这样我们就可以保留它创建的相同道具。我们可以用它React.cloneElement()来处理这个问题。

    它与参数所在的函数React.cloneElement()具有相同的API React.createElement()

    1. 我们要克隆的ReactElement
    2. 任何props我们要添加到该实例
    3. children我们想要的任何东西。

    在我们的Formatter例子中,我们创建所有的孩子列表中的一个副本(<Hour /><Minute />,等部件),并通过他们的state对象作为自己的道具。

    React.Children对象提供了一些很好的实用功能来处理孩子。我们Formatter上面的示例使用该map函数迭代子节点并克隆列表中的每个子节点。它key为每一个创造了一个(如果必要的话),使我们不必自己管理唯一性。

    让我们使用该React.Children.map()函数来更新我们的App组件:

    const App = (props) => {
      return (
        <ul>
          {React.Children.map(a, i => <li>{i}</li>)}
        </ul>
      )
    }

    回到浏览器,一切仍然有效。

    React.Children我们可用的对象中还有其他几种非常有用的方法。我们将主要使用该React.Children.map()功能,但了解其他可用的功能是很好的。查看文档以获取更长的列表。

    截至通过这一点,我们只处理本地数据,没有真正专注于远程数据(虽然我们没有建立我们的活动饲料成分时,简单地提到它)。明天我们将开始与服务器进行交互,以便我们可以在我们的React应用程序中使用它。

    今天干得好!

    学习REACT正确的方法

    React和朋友的最新,深入,完整的指南。

    下载第一章

    ❮上一个

    下一章:

    获取远程数据

    下一个 ❯

    本教程系列的完整源代码可以在GitHub repo找到,其中包括所有样式和代码示例。

    如果您在任何时候感到困难,还有其他问题,请随时通过以下方式与我们联系:

     

    展开全文
  • reactReact.createElement()方法的使用问题: 我的需求是根据给定的数据成下面这样的标签组: 1)<SubMenu title={<span><Icon type="setting" />常用查询</span>}> <Menu.Item key="query_quick"> 快速查询 ...
  • react.js基本使用

    2018-10-17 08:17:09
    js对象模拟页面上的元素,并提供操作dom对象的api,能够使页面高效刷新 解决问题? 传统的渲染方案 方案一:手动for循环整个数组,然后手动拼接字符串 方案二:使用模板引擎,art-template 当内存中的数据...
  • react.js》小书非常基础,适合入门新手,非常好理解,规定自己几天时间内阅读完并确保最基本的知识都掌握了,将一些平时回忽略的注意点做了小笔记 react简介 React.js 提供UI层面的解决方案,在实际项目中,需要...
  • 题目: 实现一个组件 BlackBorderContianer,它会把作为它的嵌套结构的 每个直接子元素 都用一个黑色边框的 div 包裹起来。例如: &amp;amp;amp;lt;BlackBorderContainer&amp;amp;amp;...
  • react.js map遍历的问题

    2019-06-29 12:01:28
    React遍历多个Ant Design中的Upload组件时,随意删除任一个Upload出现了bug,依次点击上传图片后,当点击删除时,倒着删除没有...解决方法:将map遍历中的key={index}改为key={item} import { Upload, message,...
  • 单选框 <!DOCTYPE html> <html> <head>...Hello React!...script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src.
  • React.js学习版2~

    2016-08-19 22:33:20
    我一个沉迷学习无法自拔的美男子~来更新react学习第二弹了!this.props.children this.props对象的属性与组件的属性一一对应,但是有一个例外,就是this.props.children属性。var NodesList = React.createClass({ ...
  • React.js——列表渲染

    2019-08-06 11:25:51
    同样是列表渲染,React.js个人认为略显笨拙…相比较Vue.js,可能不会太友好,但是确实ES6的语法写起来很爽…哈哈 基本格式 函数式列表组件(举例) 写法一 function list(props) { const numbers = props....
  • react提供了一个克隆 API: React.cloneElement( element, [props], [...children] ) 官方定义: Clone and return a new React element using element as the starting point. The resulting element will ...
  • React.js有一套自己调用Google Map的机制。 附链接:https://www.npmjs.com/package/google-maps-react 首先,你需要去申请一个API key。 具体的安装和使用方法在以上链接中都有,这里主要想记录一下标记地点的...
  • 错误代码: const numbers = [1,2,3,4,5]; const listItems = numbers.map(item => <li>{item}</li>) ReactDOM.render( <ul>{listItems}<...
  • React.Children详解

    2019-03-24 20:14:28
    React Children是顶层API之一;this.props.的对象属性和组件属性是一一对应的,但是有一个例外,this.props.children是组件所有的子节点 React.Children.map object React.Children.map(object children, ...
  • 学习react.js

    2016-08-09 14:12:23
    网址收集 http://www.ruanyifeng.com/blog/2015/03/react.html
  • react.js总结学习

    2017-04-01 15:16:31
    React 使用jsx来替代javascript语法。 实际上html语言直接写在javaScript语言中,这就是jsx语法,而且不加任何引号。属于javascript的语法变量使用 {} 表示。 入门实例: ReactDOM.render( ...
  • react.js 循环输出问题

    2019-05-12 13:12:10
    方法一:将要输出的列表直接保存在数组中 ...var Demo = React.createClass({ getInitialState:function(){ return {lenght:3} }, render:function(){ var items = []; for (var i = 0; i < 3; i...
  • 最近在学 React.js,也写了一些练习的项目,之前参考网上的一些代码写了一个很简单的 to-do list。对于初学者来说,写个基本的 to-do list 对于理解 React 中的一些概念及语法倒是挺有帮助的。 现在很多的 React ...
1 2 3 4 5 ... 20
收藏数 24,174
精华内容 9,669
关键字:

map使用 react.js