React 相关

React基础


React是facebook里一群牛叉的码农折腾出的牛叉的框架,实现了一个虚拟DOM,用DOM的方式将需要的组件秒价,用不着的
秒删,React扮演者MVC结构中的V的角色,不过你要是Flux搭配使用,你就有一个很牛叉的能轻松让M和V同步的框架了


一、组件们
在React中,你可以创建一个有特殊功能的组件,这在HTML元素里你是打着灯笼也找不到的,比如类似下拉导航,每个组件
都有自己的地盘(scope),所以我们定义一个组件后可以反复的用反复的用,更本就不需要和别的组件交互!
每个组件都有一个功能叫render,它可以高效的返回要射到浏览器上的HTML。我们也可以调用React的其他组件,这意味着
这一入React深似海,


JSX
如果你经常注意React你也许会发现有个东西叫JSX。JSX允许我们在Javascript中写HTML,而不是用HTML包含JavaScript。
它能帮助我们快速开发,因为我们不用担心字符串和换行等。你可以在浏览器中运行JSX,但是不推荐,因为这样会减慢
你的页面速度,gulp和grunt为你的预处理任务提供了一个JSX解释器,所以如果你想使用JSX,我建议开启这个功能。


使用JSX
如前面所说,JSX每一个组件都有一个render方法,这个方法产生一个“ViewModel(视图模型)”在返回HTML到组件之前,你可以
讲这个模型的信息放入视图中,意味着你的HTML会根据这个模型动态改变
一旦你完成了操作,就可以返回你想渲染(render)的东西,我们使用JSX来做是如此简单


var ExampleComponent = React.createClass({
render:function(){
return(
<div className="navigation">
Hello World!
</div>
);
}
});


如果你要在你的浏览器中运行这段代码,只会得到语法错误的提示,因为在JavaScript<和>字符要用引号包含起来。当你在代码上
运行JSX解释器,它将被传唤成这样


var ExampleComponent = React.createClass({
render:function (){
return(
React.createElement('div',{className:'navigation'},'Hello World!')
);
}
});


运行了!JSX解释了你使用React.createElement生成的所有DOM节点,生成了节点类型、参数和内容。你可以不用JSX,但这意味着
你必须要手动写React.createElement以外的所有DOM节点。无数例子告诉我要使用JSX。
你一定很疑惑我为什么在DOM上使用className来代替class,这是因为class是JavaScript的保留词,当JSX解释你的代码时就会改变
这节点上的所有属性到一个对象上,但你不能把对象当做属性!
将变量用在属性上
如果你想动态改变组件的样式类(或者其他任何的属性值),你可以使用变量,不过你不能只是传进去一个变量名称,你还要将其用
一对大括号包起来,这样JSX就能知道这是一个外部的变量了。


var ExampleComponent = React.createClass({
render:function(){
var navigationClass = 'navigation';
return(
<div className={navigationClass}>
Hello World!
</div>
);
}
});


初始的渲染器
当你最开始要渲染一个React组件时,你需要告诉React是要渲染什么样的组件,还要制定一个现有的DOM节点以表示在哪儿渲染
这个组件,为此你会要使用React.render函数


var ExampleComponent = React.createClass({
render:function(){
return (
<div className="navigation">
Hello World!
</div>
);
}
});
React.render(<ExampleContent/>, document.body);


他将会在body节点上渲染组件---简单吧,从此你就可以像通常那样调用其他的组件了,或者如果你希望的话,可以使用render
函数许多次,如果你不想使用React来渲染整个页面,但仍然想要使用多个组件


二、一个组件的基础


组件可以拥有自己的状态,这使得我们能够重复多次使用相同的组件但却让他们看起来完全不同,因为每个组件实例的状态是
唯一的
当你通过传递属性到一个组件时这些被称为属性。不要只局限于HTML属性,你可以传递任何你想传递的东西,并在组件内通过
this.props访问它。这样使得我们能够重复使用相同的组件但传递一组不同的属性,比如组件的“配置”,
属性
根据我们前面“Hello World!”的例子,我们在HTML节点上有className的属性,在组件内部,我们可以使用this.props.classname
访问这个值,但正如前面所述,你可以传递任何你喜欢的内容,对我们的下拉来说,我们需要将导航配置为对象,组件将使用
它作为要渲染的配置,let's start


var navigationConfig = [];
var Navigation = React.createClass({
render:function(){
return (
<div className="navigation">
</div>
);
}
});
React.render(<Navigation config={navigationConfig} />,document.body);


如果现在能访问this.props.config的话,我们会受到一个空数组(navigationConfig的值)。在我们进入到真正导航的编码钱
让我们先说明一下状态。
三、状态
如之前所说的,每一个组件都有其自己的“状态”,当要使用状态时,你要定义初始状态,然后才可以使用this.setState来更新
状态。无论何时状态得到了更新,组件都会再一次调用render函数,拿新的值去替换或者改变之前渲染的值。这就是虚拟DOM
的奥义---计算差异的算法是在React内部完成的,因此我们不用去依赖DOM的更新了(因为DOM很慢),React会计算出差异
并产生一堆指令的集合(例如:加入向“navigation_link”加入“active”类,或者移除一个节点),并在DOM上执行它们。
使用导航,我们将下拉菜单打开保持在状态中。为此,添加一个getInitialState函数到类配置对象上,并返回带有我们想要
的初始状态的对象。


var navigationConfig = [] ;
var Navigation = React.createClass({
getInitialState:function(){
return{
openDropdown:-1
};
},
render:function (){
return (
<div className="navigation">
</div>
);
}
});
React.render(<Navigation config={navigationConfig}/>,document.body);
你会发现我们将其设置成了-1。当我们准备去打开一个下拉菜单时,将使用状态里面的配置数组中的导航项的位置,而由于
数组索引开始于0,我们就得使用-1来表示还没有指向一个导航项。
我们可以使用this.state来访问状态,因此如果我们去观察atthis.state.openDropdown,应该会有-1被返回。


componentWillMount
当组件要被挂载时这个函数被调用,这意味着我们可以在此运行组件功能必须的代码,为由于render在组件生命周期里
被多次调用,我们一般会把只需要执行一次的代码放在这里,比如XHR请求


var ExampleComponent = React.createClass({
componentWillMount:function(){
//xhr request here to get data
},
render:function(){
//this gets called many times in a components life
return(
<div>
Hello World!
</div>
);
}
})

四、
componentDidMount
一旦你的组件已经运行了render函数,并实际将组件渲染到了DOM中,componentDidMount就会被调用。我们
可以在这儿做任何需要做的DOM操作,以及任何需要依赖组件已经实际存在于DOM之后才能做的事,例如渲染
一个图表,你可以通过调用this.getDOMNode在内部访问到DOM节点


var ExampleComponent = React.crateClass({
componentDidMount:function(){
var node = this.getDOMNode();
//render a chart on the DOM node
},
render:function (){
return(
<div>
Hello World!
</div>
);
}
});


componentWillUnmount
如果你准备把组件从DOM移除时,这个函数将会被调用,这让我们可以在组件背后进行清理,比如移除任何我们已经
绑定的事件监听器。如果我们没有在自身背后做清理,而当其中一个事件被触发时,就会尝试去算计一个没有载入
的组件,React 就会抛出一个错误。


var ExampleComponent = React.createClass({
componentWillUnmount:function(){
//unbind any event listeners specific to this compont
},
render:function(){
return(
<div>
Hello World!
</div>
);
}
});


五、组件方法
React也为组件提供了更方便我们工作的方法,他们会在组件的创建过程中被调用到。例如getInitialState,能让我们定义一个默认的状态,
这样我们不用担心在代码里面对状态项目是否再做进一步的检查了。
getDefaultProps
当我们创建组件时,可以按照我们的想法为组件的属性定义默认值。这意味着我们在调用组件时,如果给这些属性设置值,组件
会有一个默认的“配置”。而我们就不用操心在下一行代码中检查属性这类事情了。
当你定义了组件时,这些默认的属性会被缓存起来,因而针对每个组件的实例她们都是不一样的,并且不能被改变,对于导航组件
我们将配置指定为一个空的数组,因而就算没有传入配置,render方法内也不会发生错误。


var Navigation = React.createClass({
getInitialState:function() {
return {
openDropdown:-1
};
},
getDefaultProps:function (){
return {
config:[]
}
},
render:function (){
return (
<div className="navigation">
</div>
);
}
});
React.render(<Navigation config={navigationConfig}/>,document.body);


propTypes
我们也可以随意为每一个属性指定类型。这对于我们检查和处理属性的意外赋值非常有用。如下面的dropdown,我们指定只有
数组才能放入配置。


var Navigation = React.createClass({
getInitialState:function(){
return{
openDropdown:-1
};
},
getDefaultProps:function(){
return{
config:[]
}
},
propTypes:{
config:React.PropTypes.array
},
render:function (){
return(
<div className="navigation">
</div>
);
}
});
React.render(<Navigation config={navigationConfig}/>,document.body);


六、mixins


我们也可以在组件中加入mixins.这是一个独立于React的基本组件(只是一个对象类型的配置),这意味着,如果我们有两个
功能类似的组件,就可以共享一个配置了(如果初始状态相同),我们可以抽象化地在mixin中建立一个方法,这样就
不用把相同的代码写上两次了。
var ExampleMixin = {
componentDidMount:function(){
//bind some event listeners here
},
componentWillUnmount:function(){
//unbind those events here!
}
};
var ExampleComponent = React.createClass({
mixins:[ExampleMixin],
render:function(){
return (
<div>
Hello World!
</div>
);
}
});


var AnotherComponent = React.createClass({
mixins:[ExampleMixin],
render:function(){
return(
<div>
Hello World!
</div>
);
}
});


这样全部组件都有一样的componentDidMount和componentWillUnmount方法了,保存我们重写的代码,无论如何,你不能override
(覆盖)这些属性,如果这个属性是在mixin里设置的,它在这个组件中是不可覆盖的。


七、遍历循环


当我们有一个对象的数组,如何循环这个数组并渲染每一个对象到列表项中,JSX允许你在任意Javascript文件中使用它,你可以
映射这个数组并返回JSX,然后使用React去渲染。
var navigationConfig = [
{
href:'http://ryanclark.me',
text:'My Website'
}
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item) {
            return (
                <li className="navigation__item">
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                </li>
                );
        });
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);


导航配置由数组和对象组成,包括一个指向超链接的href和一个用于显示的text属性,当我们映射的时候,他会一个个依次
通过这个数组去取的对象,我们可以访问href和text,并在HTML中使用,当返回列表时,这个数组里的列表项都将被替换
所以我们把它放入React中处理时它将知道怎么去渲染了!


八、混编


当目前为止,我们已经做到了所有下拉列表的展开,我们需要知道接下来的项目是哪个,我们将使用.children属性去遍历
我们的navigationConfig数组,接下来,我们可以通过循环来操作下拉的子元素条目。


var navigationConfig = [
    {
        href: 'http://ryanclark.me',
        text: 'My Website',
        children: [
            {
                href: 'http://ryanclark.me/how-angularjs-implements-dirty-checking/',
                text: 'Angular Dirty Checking'
            },
            {
                href: 'http://ryanclark.me/getting-started-with-react/',
                text: 'React'
            }
        ]
    }
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item) {
            var children, dropdown;
            if (item.children) {
                children = item.children.map(function (child) {
                    return (
                        <li className="navigation__dropdown__item">
                            <a className="navigation__dropdown__link" href={ child.href }>
                                { child.text }
                            </a>
                        </li>
                    );
                });
                dropdown = (
                    <ul className="navigation__dropdown">
                        { children }
                    </ul>
                );
            }
            return (
                <li className="navigation__item">
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                    { dropdown }
                </li>
                );
        });
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);


但是我们换是能看见下来条目,尽管我们将openDropdown设置成了-1.
我们可以通过在组件中访问this.state,来判断是否被打开了,我们可以为其添加一个新的css样式class来展现鼠标hover效果


var navigationConfig = [
    {
        href: 'http://ryanclark.me',
        text: 'My Website',
        children: [
            {
                href: 'http://ryanclark.me/how-angularjs-implements-dirty-checking/',
                text: 'Angular Dirty Checking'
            },
            {
                href: 'http://ryanclark.me/getting-started-with-react/',
                text: 'React'
            }
        ]
    }
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    openDropdown: function (id) {
        this.setState({
            openDropdown: id
        });
    },
    closeDropdown: function () {
        this.setState({
            openDropdown: -1
        });
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item, index) {
            var children, dropdown;
            if (item.children) {
                children = item.children.map(function (child) {
                    return (
                        <li className="navigation__dropdown__item">
                            <a className="navigation__dropdown__link" href={ child.href }>
                                { child.text }
                            </a>
                        </li>
                    );
                });
                var dropdownClass = 'navigation__dropdown';
                if (this.state.openDropdown === index) {
                    dropdownClass += ' navigation__dropdown--open';
                }
                console.log(this.state.openDropdown, index);
                dropdown = (
                    <ul className={ dropdownClass }>
                        { children }
                    </ul>
                );
            }
            return (
                <li className="navigation__item" onMouseOut={ this.closeDropdown } onMouseOver={ this.openDropdown.bind(this, index) }>
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                    { dropdown }
                </li>
                );
        }, this);
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);




鼠标滑过My Website,下拉即会出现。
在前面,我们已经给每个列表项添加了鼠标事件,如你所见,我用的是.bind调用,而非其他的方式调用,这是因为,当用户鼠标划出
元素区域,我们并不用关注光标在哪里,所以我们需要知道的是,将下拉关闭掉,所以我们可以将它的值设置为-1,但是,我们要知道
当用户鼠标划入哪个元素区域的时候下拉展开了,所以我们需要知道该参数,我们使用绑定的方式去调用而非简单的透过函数去调用
是因为我们需要通过React去调用,如果我们直接调用,那我们就需要一直调用,而不是在事件中调用它
现在我们可以添加很多的条目到navigationConfig当中,而且我们也可以给他添加样式到下列功能中


总结:
React是一个简洁方便易用而又强大的框架。它简洁的API,可以让人快速的创建自己的组件,而不去理会复杂的dom,也不用做某些
特别负责的操作,特别是在重复列表项等上面表现不错。
来源:http://www.oschina.net/translate/getting-started-with-react
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值