加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

react学习

发布时间:2020-12-15 05:18:48 所属栏目:百科 来源:网络整理
导读:http://www.cnblogs.com/alsy/p/5372770.html react实战 GitHub上给出 react 的三个关键点: 1.Just the UI (仅 仅 是view层) 2.Virtual Dom (虚拟Dom) 3.Data flow (数据流是沿着组件树从上到下单向流动的) 理解react可以参考 这里、这里, 还有 深入浅出Rea

http://www.cnblogs.com/alsy/p/5372770.html

react实战

GitHub上给出react的三个关键点:

1.Just the UI (仅是view层)

2.Virtual Dom (虚拟Dom)

3.Data flow (数据流是沿着组件树从上到下单向流动的)

理解react可以参考这里、这里,还有深入浅出React一、二、三、四。

以练手的博客为例。(学习新技术最快的途径就是实践,解决问题不断提高)【完整代码】

react强调组件的开发方式,类似于搭积木。将一个网页拆分成一个个的组件,组件可以复用,组件之间可以嵌套使用,嵌套组件之间通过属性(props)通信。

比如首页被拆分成:<Nav />、<ContainerLeft />、<Home />、<Article/>、<Footer />

render() {
        let nav = this.state.category;
        return (
            <div>
                <Nav nav={nav} />
                <div className="container">
                    <div className="row">
                        <div className="col-md-3">
                            <ContainerLeft/>
                        </div>
                        <div className="col-md-9">
                            <div id="container-right">
                                {/* <RouteHandler/> */}
                                <RouteHandler/>
                            </div>
                        </div>
                    </div>
                </div>
                <Footer/>
            </div>
        );
    }

上面的<Home />是由<Route />组件中的默认路由,了解react-router.

1
2
3
4
5
<Route name= "app" path= "/" handler={App}>
<<span style= "background-color: #888888;" >DefaultRoute</span> name= "home" handler={<span style= >Home</span>}></<span style= >DefaultRoute</span>>
"category" "/category/:categoryId" handler={Category}/>
"details" "/details/:articleId" handler={Details}/>
</Route>

这样首页就拆分成了一个个组件,图中可以看到<Home />里面包含<Article />。

<Home />组件中在组件挂载之前初始化state值为{details:[]},组件挂载执行render(),组件挂载完成时请求文章的数据detail.json(模拟的前台数据)并设置state值。state改变触发render()执行。

let Home = React.createClass({
  getInitialState() {
    return {
      details: []
    };
  },loadCommentsFromServer() {
    let self = this;
    $.ajax({
      url: './mock/detail.json',dataType: 'json',success: function(r) {
        if(200 == r.errCode){
          AppF.articleCut(r.data,config.indexShowNum,(detailsCuted) => {
            AppF.timeToStr(detailsCuted,(detailsStrTime) => {
              AppF.isStrCut(detailsStrTime,'title',config.indexTitleLength,(details) => {
                AppF.isStrCut(details,'content',config.indexContentLength,(details) => {
                  self.setState({details: details || []});
                });
              });
            });
          });
        }
      },error: function(xhr,status,err) {
        console.error(xhr,err.toString());
      }
    });
  },componentDidMount() {
    this.loadCommentsFromServer();
  },render() {
    let details = this.state.details;
    console.log("Home -- render()");
    return(
      <div>
        <div className="headline">文章<span className="font-green">推荐</span></div>
        <Articles details={details}/>
      </div>
    );
  }
});

<Home />向<Article />中传值是通过属性(props)details,这是组件之间通信的一种方式。

<Article />组件中通过this.props.details取得<Home />传过来的属性值,使用map()去遍历数组,<Link />是react-router提供的一个组件,类似于<a>链接

let Article = React.createClass({
    render() {
        let details = this.props.details;
        details = details.map( (item,index) => {
            return (
                <article key={"article-" + index}>
                    <div className="title" title={item.title}>
                        <Link to="details" params={{articleId: item.id}} title={item.title}>
                            <i className="glyphicon glyphicon-triangle-right icon-title"></i>
                            &nbsp;{item.title}
                        </Link>
                    </div>
                    <div className="row">
                        <div className="col-md-3">

                            <img className="img-thumbnail" src ={ "../vendor/images/" + item.img_file }/>
                        </div>
                        <div className="col-md-9">
                            <div className="content">
                                <p>{item.content}</p>
                            </div>
                        </div>
                    </div>
                    <div className="row sub-title">
                        <div className="col-md-3"><i className="glyphicon glyphicon-time"></i>&nbsp;{item.create_time}</div>
                        <div className="col-md-2"><i className="glyphicon glyphicon-folder-open"></i>&nbsp;&nbsp;{item.category}</div>
                        <div className="col-md-2"><i className="glyphicon glyphicon-eye-open"></i> {item.hits}</div>
                        <div className="col-md-5">
                            <Link to="details" params={{articleId: item.id}}  className="btn btn-success btn-sm pull-right btn-read-all" title={item.title}>阅读全文>></Link>
                        </div>
                    </div>
                </article>
            );
        });
        return(
            <div>
                <div className="article-list">
                    {details}
                </div>
            </div>
        );
    }
});

其他组件类似的这样搭建,这样首页就出来了。在点击有<Link to="details" params={{articleId: item.id}}/>形成的链接,<Route />组件路由到<Details />组件,并传递了参数{articleId: item.id}。

<Details />组件中通过this.props.params.articleId取得传递过来的参数。

let Details = React.createClass({
    getInitialState() {
        return {
            threeArticle: []
        };
    },loadCommentsFromServer() {
        console.log("loadCommentsFromServer");
        let self = this;
        $.ajax({
            url: './mock/detail.json',255); line-height:1.5!important">function(r) {
                if(200 == r.errCode){
                    var details = r.data;
                    AppF.articleSort(details,'id','ase',(details) => {
                        AppF.timeToStr(details,(details) => {
                            var details = details;
                            self.getArticleKey(details,self.props.params.articleId,(key) => {
                                self.getThreeArticle(details,key,(threeArticle) => {
                                    //console.log(threeArticle);
                                    self.setState({
                                        threeArticle: threeArticle[0]
                                    });
                                });
                            });
                        });
                    });
                }
            },err) {
                console.error(xhr,err.toString());
            }
        });
    },componentWillMount(){
        console.log("Details -- componentWillMount");
        this.loadCommentsFromServer();
    },当组件在页面上渲染完成之后调用
    componentDidMount() {
        console.log("Details -- componentDidMount");
    },0); line-height:1.5!important">在组件接收到新的 props 的时候调用。在初始化渲染的时候,该方法不会调用。
    componentWillReceiveProps(nextProps) {
        console.log("Details -- componentWillReceiveProps");
        this.state.threeArticle);
        return(
            <div>
                <Article article={this.state.threeArticle}/>
            </div>
        );
    },getThreeArticle(details,cb) {
        var arr = [];
        var length = details.length;
        if( length == 0 || key === ''){
            cb([]);
        } else if(length == 1){
            arr.push({pre: {},cur: details[0],next: {} });
        } else {
            if(key == 0){
                arr.push({pre: {},cur: details[0],next: details[1] });
            } if (key == length - 1){
                arr.push({pre: details[length - 2],cur: details[length - 1],next: {} });
            } else {
                arr.push({pre: details[key - 1],cur: details[key],next: details[key + 1] });
            }
        }
        cb(arr);
    },getArticleKey(details,article_id,255); line-height:1.5!important">if(0 == details.length){
            cb('');
        } else {
            details.forEach(function(item,k){
                if(item['id'] == article_id){
                    cb(k);
                }
            });
        }
    }
});

<Details />组件里包含了<Article />组件,同样的通过属性article传递数据。同样的<Article />组件中通过this.props.article来取得<Deatils />传递过来的article属性。

就可以得到文章详情页的效果了:

这时出现了一个问题:在我点击下一篇时我想让对应的导航条在相应的分类下加上我的active样式,这时设及到我要在<Article />组件中绑定事件,获取DOM的属性,向<Nav />组件传递数据。注意此时的<Nav />组件和<Article />组件并没有什么嵌套关系。

let Article = React.createClass({
    changeNavClassPre: function(e){
        console.log("Article -- changeNavClassPre");
        let cid = React.findDOMNode(this.refs.articlePre).getAttribute("data-category-id");
        PubSub.publish(EventName.navClass,{categoryId: cid});
    },changeNavClassNext: this.refs.articleNext).getAttribute("data-category-id");
        PubSub.publish(EventName.navClass,render() {
        let threeArticle = .props.article;
        let cur,pre,next;
        console.log(threeArticle);
        $.each(threeArticle,(item,value) => {
            if(item == 'cur'){
                cur = (
                    <div>
                        <div className="col-md-12 article-title">{value.title}</div>
                        <div className="col-md-12 article-icon">
                            <ul>
                                <li>
                                    <i className="glyphicon glyphicon-folder-open"></i>&nbsp;{value.category}
                                </li>
                                <li>
                                    <i className="glyphicon glyphicon-time"></i>&nbsp;{value.create_time}
                                </li>
                                <li>
                                    <i className="glyphicon glyphicon-eye-open"></i>&nbsp;{value.hits}人阅读
                                </li>
                            </ul>
                        </div>
                        <div className="col-md-12">
                            <p className="article-content">{value.content}</p>
                        </div>
                        <div className="col-md-12 article-icon">
                            <ul>
                                <li>
                                    <a href="javascript:;"><i className="glyphicon glyphicon-thumbs-up"></i>&nbsp;赞</a>
                                </li>
                                <li>
                                    <i className="glyphicon glyphicon-comment"></i>&nbsp;0人评论
                                </li>
                            </ul>
                        </div>
                    </div>
                );
            } if(item == 'pre'){
                if(!value.id){
                    pre = (
                        <p className="article-pre">
                            <i className="glyphicon glyphicon-chevron-up"></i>&nbsp;上一篇:无
                        </p>
                    );
                } else {
                    pre = (
                        <p className="article-pre" data-category-id={value.category_id} onClick={this.changeNavClassPre} ref="articlePre">
                            <Link
                                to="details"
                                params={{articleId: value.id}}
                                title={value.title}>
                                <i className="glyphicon glyphicon-chevron-up"></i>
                                &nbsp;上一篇:{value.title}
                            </Link>
                        </p>
                    );
                }
            } else {
                if(!value.id){
                    next = (
                        <p className="article-pre">
                            <i className="glyphicon glyphicon-chevron-down"></i>&nbsp;下一篇:无
                        </p>
                    );
                } else {
                    next = (
                        <p className="article-pre" data-category-id={value.category_id} onClick={this.changeNavClassNext} ref="articleNext">
                            <Link
                                to="details"
                                params={{articleId: value.id}}
                                title={value.title}>
                                <i className="glyphicon glyphicon-chevron-down"></i>
                                &nbsp;下一篇:{value.title}
                            </Link>
                        </p>
                    );
                }
            }
        });
        return (
            <div className="row">
                {cur}
                <div className="col-md-12" id="pre-next">
                    {pre}
                    {next}
                </div>
            </div>
        );
    }
});

这里需要注意:

1.React并不会真正的绑定事件到每一个具体的元素上,而是采用事件代理的模式:在根节点document上为每种事件添加唯一的Listener,然后通过事件的target找到真实的触发元素。这样从触发元素到顶层节点之间的所有节点如果有绑定这个事件,React都会触发对应的事件处理函数。这就是所谓的React模拟事件系统。

2.如果你要获取原生的Dom,然后进行相关Dom操作,你可以给你想要获得的标签内分配ref属性(比如ref="articleNext"),然后在组件内React.findDOMNode(this.refs.articleNext)获得对应的Dom,然后就可以愉快的操作Dom了。

3.React高效的Diff算法。这让我们无需担心性能问题,由虚拟DOM来确保只对界面上真正变化的部分进行实际的DOM操作。

那么就剩下如何向<Nav />组件传递消息了,这里我采取的是订阅发布模式(观察者模式)来进行通信的。引用PubSubJS

首先在<Nav />中,我们订阅了navClass这么一个事件

    componentDidMount: function () {
        console.log("Nav -- componentDidMount");
        token = PubSub.subscribe(EventName.navClass,this.changeActive);
    },changeActive: function(msg,data){
        console.log(data);
        let self = $('#navbar-nav li[data-active="' + data.categoryId +'"]');
        $('#navbar-nav li').removeClass('active');
        self.addClass('active');
        self.parents("li.dropdown").addClass('active');
    },componentWillUnmount: function () {
        console.log("componentWillUnmount");
        PubSub.unsubscribe( token );
    }

在<Article />组件中去发布这个事件,并且传递了{categoryId: cid}过去

changeNavClassPre: this.refs.articlePre).getAttribute("data-category-id");
        PubSub.publish(EventName.navClass,{categoryId: cid});
    },255); line-height:1.5!important">this.refs.articleNext).getAttribute("data-category-id");
         
     
   

<Nav / >就可以去响应这个事件,相应的去操作Dom.这样就实现了不是嵌套关系的组件之间的通信。

说到这里,对于数据的请求、数据的变化等场景,可以使用Flux、Relay、GraphQL来处理。

注:入门react,个人观点有误请指正,不足请提出。

分类: web

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读