React作为三大主流框架之一,有着很好的灵活性,兼容性和单向数据流的特性,本人学习了两周React,东西多而杂,决定花点时间把之前零碎的基础知识点和容易混淆的知识点给梳理一遍,加深理解,方便以后开发、学习使用。
一 、元素渲染和JSX
元素渲染
1. 在HTML里面添加一个<div>标签,<div>中所有的元素将会由ReactDOM来管理,我们称之为根节点。要将React元素渲染到DOM中,通过使用ReactDOM.render()方法来进行渲染。
<div id="example"> </div>
const element=<h1>hello,world </h1>
ReactDOM.render(
element,
document.getElementById("example")
)
2.React更新元素渲染
React在执行更新时只会更新部分,把DOM中更改的部分通过ReactDOM.render()方法来更改只发生改变的内容。
注意:在ES6继承React.Component组件中,在render()方法中使用this.props来替换props。
3.在render()方法中,返回标签时,允许返回多个HTML标签,但是要使用一个<div> </div>标签包裹起来
JSX
1.独立文件。ReactJS可以在一个独立的文件里,引入的方式和javascript方式一样
2.Javascript表达式。
3.样式。可以声明一个样式,然后使用{{}}来引用,如
var myStyle={color:'#FFF00',fontSize:10}, <h1 style={{myStyle}}>我的JSX样式 </h1>
4.注释。使用{/**/}
5.数组。React中使用数组可以直接使用{arr}来引用,React自动展开数组中的所有
6.自定义属性,标签p元素中要添加自定义元素时,需要使用data-myattribute,如
<p data-myattribute="color:red">百度一下 </p>
二、组件
组件介绍
1. React组件是我们写代码中最常见的元素,组件能够让我们在开发中能够更容易管理,直观亲切,由于规范,组件名的首字母一般使用大写,继承React.Component的类首字母一般要求大写,否则会出错:
2. 定义组件的三种方式:函数定义,用户自定义组件,继承React.Component定义。组件将我们的应用模块化,每个模块之间可以通过合适的方式进行联系。
函数定义:
function Mycomponent(){ }
用户自定义组件:
const hello=<Hello />
使用ES6方式定义:
class Mycomponent extends React.Component{}
组件 API
今天只介绍setState()方法,学习和开发中经常用到的:
设置状态:setState()
setState(object nextState[,callback])
参数说明:
nextState表示下一个状态,该状态会和当前状态进行合并,比如我们在一个事件中,点击按钮,触发事件,按钮的状态发生改变。
this.setState(preState=>{isToggleOn:!preState.isToggleOn})
//箭头函数和this的使用及注意事项在后面再统一整理
组件生命周期
React组件的生命周期方法有:
componentWillMount()和componentWillUnmout():
componentWillMount()在render()方法执行前调用,即页面渲染前调用,在客户端也在服务端。componentWillUnmout()用来释放资源,在组件移除DOM的时候立刻调用。
看以下代码:
<script type="text/babel">
class Mycomponent extends React.Component{
componentWillMount(){
console.log("在渲染前调用")
}
render(){
console.log("进入到render方法")
return(
<h1>返回一个componentWillMount</h1>
)
}
}
ReactDOM.render(
<Mycomponent />,
document.getElementById("example")
)
</script>
打印结果如下:
在渲染前调用
进入到render方法
componentDidMount():
在第一次渲染后调用,只在客户端,之后组件就生成了对应的DOM结构,在这个方法里面一般可以设置定时器,发送ajax请求等。
看以下代码,在componentDidMount()方法里面设置定时器:
class Mycomponent extends React.Component{
constructor(props){
super(props);
this.state={date:new Date()}
}
//使用箭头函数可以获取上下文的this
componentDidMount(){
this.timerId=setInterval(
()=>this.tick(),
1000)
}
//此写法需要绑定this,因为默认是没有绑定this,不绑定会报错tick找不到
// componentDidMount(){
// this.timerId=setInterval(
// this.tick.bind(this) ,1000)
// }
// }
//也可以使用let声明一个变量,来获取到this
// componentDidMount(){
// let that=this;
// this.timerId=setInterval(function(){
// return that.tick();
// },1000)
// }
tick(){
this.setState(
{date:new Date()}
)
}
componentWillUnmout(){
clearInterval(this.timerId)
}
render(){
return(
<h1>现在是北京时间:{this.state.date.toLocaleTimeString()}</h1>
)
}
}
ReactDOM.render(
<Mycomponent />,
document.getElementById("example")
)
此处注意:this的绑定问题,官方文档给出class方法默认是不绑定this。
接下来我们在componentDidMount()方法里面使用ajax请求,使用jquery的方式和fetch请求方式来请求,用componentWillUnmout()来释放资源。
第一种方式比较普遍的请求方式,jquery方式请求:
第一步引入jq文件:
<script type="text/javascript" src="../js/jquery-3.1.1.min.js"></script>
请求格式: $.get(url,callback),准备的url为:
https://api.github.com/users/octocat/gists
我们的目的是获取到对应的username和最后更新地址:username,lastGistUrl
直接看代码:
<script type="text/babel">
class UserGist extends React.Component{
constructor(props) {
super(props);
this.state = { username: "", lastGistUrl:"" };
}
componentDidMount(){
//先执行Ajax数据请求
this.serverRequest = $.get(
this.props.source, function (result) {
var lastGist = result[0]; //在根据数据更新组件状态
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
});
}.bind(this)
);
}
componentWillUnmount(){
this.serverRequest.abort();
}
render(){
return (
<div> {this.state.username}
用户最新的 Gist 共享地址:
<a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a>
</div> );
}
}
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists"/> ,document.getElementById('example')
)
</script>
打印结果为:
注意点:
1.如果我在callback中不绑定this,则会出现this.setState is not a function异常。
2.ajax请求的url返回的是地址下的所有资源,选择使用了result[0]。
3.在componentWillUnmout()方法里面卸载资源。
第二种方式,使用fetch,请求的格式为:
fetch(url).then(res=>res.json).then((result)=>{this.setState(){state:value}})
<script type="text/babel">
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { error: null, isLoaded: false, items:[] };
}
componentWillMount(){
console.log("使用react请求ajax的准备")
}
componentWillUnmount(){
}
componentDidMount() {
fetch("https://api.github.com/users/octocat/gists")
.then(res => res.json())
.then( (result) => {
this.setState({
isLoaded: true,
items:result
});
},
//我们在此处使用error
(error) => {
this.setState({
isLoaded: true,
error
});
} )
}
render() {
const { error, isLoaded,items} = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul> {
items.map(item => (
<li key={item.url}> url:{item.url}_________forks_url:{item.forks_url} </li>
))
}
</ul>
);
} } }
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
)
</script>
打印结果如下,先会加载出Loading...然后显示结果:
注意:
1.在遍历列表时,先要用{}来遍历出列表中的所有<li>,然后给<li>标签指定一个key。
2.在回调函数中使用erro数组来存放出错的消息,并对error进行状态判断,然后选择性的条件渲染。
三、箭头函数和this使用注意事项
1.箭头函数与function函数的写法区别:
//function
var fn=function(a,b){
return a+b;
}
//箭头函数
var fn=(a,b)=>{return a+b};
2.this的指向
//使用function定义的函数
function fn(){
console.log(this);
}
var obj = { ob: fn};
fn(); //打印Window
obj.ob() //obj { ob: fn}
//下面我们使用箭头函数定义函数
var fn = () => { console.log(this) };
var obj = { ob:fn };
fn(); //Window
obj.ob(); //Window
由此可见this在箭头函数中的指向没有发生改变。测试如下:
<script type="text/javascript">
var fruit="banana";
var o={
fruit:"apple",
foo:foo
}
function foo(){
console.log(this.fruit);
}
function a(){
foo();
}
function b(){
o.foo();
}
var c=()=>{
console.log(this);
}
var obj={fn:c};
function d(){
obj.fn();
}
</script>
</head>
<body>
<!-- this的指向是运行时绑定的 -->
<button onClick="a()">全局的this</button>
<button onClick="b()">指向对象</button>
<button onclick="c()">箭头函数的this</button>
<button onclick="d()">使用对象来获取</button>
</body>
打印结果如下:
3.箭头函数的详细用法
直接上代码,下面请看各种箭头函数的详细用法:
<!--箭头函数的使用-->
<script type="text/babel">
//1.单一参数的箭头函数 const fn=foo=>'我是一个快乐的小青蛙!'; //单引号'和`都可以
console.log(fn('测试!')); //我是一个快乐的小青蛙,测试!
//2.单行函数返回一个对象字面量,注意返回的结果需要使用括号包裹,不能直接使用大括号,否则浏览器会将其解析为一个多行箭头函数
const ids=[1,2,3];
const users=ids.map(
(a,id)=>({a:a,content:id})
)
console.log(users);
//3.多参数的箭头单行函数
const fn1=(a,b)=>a+b;
console.log(fn1(1,2)); //3
//4.单参数的多行箭头函数
const fn2=a=>{
if(a=='number'){
console.log("number");
}else{
console.log("string");
}
}
fn2("1");
//5.多参数的多行箭头函数,与上面相比参数为2个及以上
const fn3=(a,b)=>{
if(a+b>10){
console.log("大于10");
}else{
console.log("小于等于10")
} }
fn3(5,6);
//无参数箭头函数,此处使用括号来替代无参
const fn4=()=>"ES6"; console.log(fn4());
</script>
<script type="text/javascript">
//等同于上面的const fn=foo=>foo;
var fn=function(foo){
return foo;
}
console.log(fn('测试')); </script>
</body>
打印结果为: