一、HTML模板
React的网页源码大致如下:
<!DOCTYPE html> <html> <head> <script src="../build/react.js"></script> <script src="../build/react-dom.js"></script> <script src="../build/browser.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> // ** Our code goes here! ** </script> </body> </html>
<script type="text/babel"></script>,这个type的属性为text/babel,这是因为JSX语法和JavaScript语法不兼容,凡是遇到JSX语法的网页都需要把文档类型设置为babel。上述代码引用的三个库react.js(react的核心库)/react-dom.js(react-dom库,提供和DOM有关的功能)/browser.js(将JSX转换成JavaScript语法,耗时比较久,生产环境下我们通常放在服务器上),都必须提前加载。
二、ReactDOM.render()
ReactDOM.render是React的最基本方法,用于将模板转换为HTML语言,并插入在制定的DOM节点中。
ReactDOM.render( <h1>Hello</h1>, document.getElementByID('body') )
将h1标签插入到id为body的DOM节点中。
三、JSX语法:
JSX语法允许将XML代码直接写在JS里,不需要加任何引号。基本语法规则:遇到XML标签(以<开头),就按照XML语法来解析,遇到代码块(以{}为标志),就以JavaScript语法来解析。XML不是HTML,所以所有的标签都需要闭合。
var arr = ['a', 'b', 'c']; ReactDOM.render( <div> { arr.map(function(e){ return <div>Hello, {e}</div> }) } </div>, document.getElementById('example') )
JSX允许将模板直接插入到JavaScript变量中,如果变量是一个数组,会展开这个数组里面的所有成员。
var arr = [ <h1>Hello world!</h1>, <h2>React is awesome</h2>, ]; ReactDOM.render( <div>{arr}</div>, document.getElementById('example') );
四、组件
React允许将代码封装成组件,然后像插入普通HTML标签一样,在网页中插入这个组件。React.createClass方法用于生成这样一个组件类。
var HelloMessage = React.createClass({ //组件名字的首字母必须大写,且返回的实例必须有且只有一个顶级标签 render: function(){ return <h1>{this.props.name}</h1> } }) ReactDOM.render( <HelloMessage name="ccc" />, //添加属性的时候注意保留字,类用className,for属性需要写成htmlFor document.getElementById( 'example' ); );
变量HelloMessage是一个组件类,模板插入<HelloMessage />时,会自动创建一个组件类的实例,可以自己添加属性,所有的组件类都必须有自己的render方法,用于输出组件(即实例)。
特别注意:此处的创建组件类的方法已经过时,将本文中所有涉及到定义组件类的代码均改为:
class Welcome extends React.Component{ render(){ return <h1>Hello, {this.props.name}</h1>; } }
带属性props的可以使用函数声明类的方法,函数形式的组件不支持state:
function Welcome(props){ return <h1>Hello, {props.name}</h1>; }
更简洁。
五、this.props.children
this.props对象的属性和组件的属性是一一对应的,但是有一个例外,就是this.props.children,它表示组件的所有子节点。
var Nodelist = React.createClass({ render: function(){ return ( <ol> React.children.map(this.props.children, function(child){ return <li>{child}</li> }) </ol> ); } }); ReactDOM.render( <Nodelist> <span>Hello</span> <span>Hi</span> </Nodelist> )
上述例子中的两个span子元素使用this.props.children遍历。如果当前组件没有子节点,this.props.childre返回的是undefined,如果有一个子节点,返回的是一个对象,如果是多个子节点,返回的是一个array类型的数据。
React提供了一个方法React.children来处理this.props.children,我们使用React.children.map的方法遍历子节点就不需要考虑到底有几个子节点以及他们的数据类型了。
六、PropTypes
组件的属性可以是好多种类型,有时候我们需要在别人使用我们的组件时检查他们提供的参数是否符合我们要求。组件类的PropTypes就是用来检查组件实例的属性是否符合要求的。栗子:
var Test = React.createClass({ propTypes: { title: React.PropTypes.string.isRequired, // 检查组件实例的title属性必填且为字符串。 }, render: function(){ return <h1>Hello World</h1> } });
还有设置属性默认值的方法:getDefaultProps
getDefaultProps: function(){
return{
title: 'Hello World'
}
}
七、获取真实的DOM节点
组件并不是真实的DOM节点,而是存在于内存之中的一种数据结构---虚拟DOM。只有当它插入到文档后才能变成真实的DOM。根据React的设计,所有的变动都先发生在虚拟DOM上,然后再将实际发生变动的部分反映在真实的DOM上,这种做法叫DOM diff。但是有时候我们需要从组件获取真实DOM节点,这时就要用到ref属性。
var MyComponent = React.createClass({ handleClick: function() { this.refs.myTextInput.focus(); }, render: function() { return ( <div> <input type="text" ref="myTextInput" /> <input type="button" value="Focus the text input" onClick={this.handleClick} /> </div> ); } }); ReactDOM.render( <MyComponent />, document.getElementById('example') );
文本输入框要获取用户的输入就一定要是真实的DOM,this.ref.[refName]获取的是真实的DOM节点,必须等到虚拟DOM插入文档之后才能使用这个属性,否则会报错,上述例子是在onclick回掉函数的时候使用的,此时已经插入到文档中了。
八、this.state
React将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染UI。
var LikeButton = React.createClass({ getInitialState: function() { // 这个方法用于定义组件的初始状态,可以使用this.state读取 return {liked: false}; }, handleClick: function(event) { this.setState({liked: !this.state.liked}); }, render: function() { var text = this.state.liked ? 'like' : 'haven\'t liked'; return ( <p onClick={this.handleClick}> You {text} this. Click to toggle. </p> ); } }); ReactDOM.render( <LikeButton />, document.getElementById('example') );
当用户点击组件时,导致状态变化,this.setState就修改状态值,每次修改以后,自动调用this.render方法,再次渲染组件。
this.props和this.state的区别:
都用于描述组件的特性,this.props表示那些一旦定义就不会再改变的特性,而this.state是随着用户互动而产生变化的特性。
九、表单
用户在表单中填入的内容属于用户组件之间的互动,不能使用this.props
var Input = React.createClass({ getInitialState: function() { return {value: 'Hello!'}; }, handleChange: function(event) { this.setState({value: event.target.value}); }, render: function () { var value = this.state.value; return ( <div> <input type="text" value={value} onChange={this.handleChange} /> <p>{value}</p> </div> ); } }); ReactDOM.render(<Input/>, document.body);
文本输入框的值不能用this.props.value读取,而要定义一个onChange时间的回调函数,通过event.target.value来获取。textarea/select/radio都属于这种情况。
十、组件的生命周期
组件的生命周期分为三种状态:
Mounting:已插入真实DOM
Updating:正在被重新渲染
Unmounting:已移除真实DOM
React为每种状态提供了两种处理函数,will函数在进入状态之前调用,did在进入状态之后调用,三种状态共计五种处理函数。
componentWillMount()
componentDidMount()
componentWillUpdate( object nextProps, object nextState )
componentDidUpdate( object prevProps, object prevState )
componentWillUnmount()
还有两种特殊的处理函数:
componentWillReceiveProps( object nextProps ):已加载组件收到新的参数时调用
shouldComponentUpdate( object nextProps, object nextState ):组件判断是否重新渲染时调用
var Hello = React.createClass({
getInitialState: function () {
return {
opacity: 1.0
};
},
componentDidMount: function () {
this.timer = setInterval(function () {
var opacity = this.state.opacity;
opacity -= .05;
if (opacity < 0.1) {
opacity = 1.0;
}
this.setState({
opacity: opacity
});
}.bind(this), 100);
},
render: function () {
return (
<div style={{opacity: this.state.opacity}}> //注意写法不要写成style="opacity:{this.state.opacity};",第一层{}是JS语法,第二层是style对象
Hello {this.props.name}
</div> );
}
});
ReactDOM.render( <Hello name="world"/>, document.body );
mount 挂载:这个过程暴露的几个钩子:
constructor()
componentWillMount()
render()
componentDidMount()
update 更新:
componentWillReceiveProps(nextProps)
shouldComponentUpdate(nextProps, nextState)
componentWillUpdate()
render()
componentDidUpdate()
unmount 移除
componentWillUnmount()
一般这三个钩子里设置setState
componentWillMount()
componentDidMount()
componentWillReceiveProps()
十一、AJAX
组件的数据来源通常都是Ajax请求服务器获取的,可以用componentDidMount方法设置Ajax请求,成功后再用this.setState重新渲染。
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> ); } }); ReactDOM.render( <UserGist source="https://api.github.com/users/octocat/gists" />, document.body );
React本身没有任何依赖,完全可以不用jquery,而是用其他库。
以上内容均来自阮一峰大神的教程,只是当学习笔记来整理的:
链接:http://www.ruanyifeng.com/blog/2015/03/react.html
注意注意注意:本文中涉及到的定义类的方法(React.createClass)已过时,均改为class Welcome extends React.Component。
补充:1、在本地新建一个react项目的步骤。
首先在命令行中执行:npm install -g create-react-app (最好在执行前先安装yarn)
然后create-react-app . (如果想看例子的话就把.换成hello-world) 还有 这个项目的根目录的名字里不能含有大写字母,否则yarn start的时候会报错
然后 yarn start
2、将本地的react项目推到远程git仓库
依次执行下面的命令:
git init
git config user.name ccclarity
git config user.email 1227039581@qq.com
git add .
git commit -m 'add'
git remote add origin git@github.com:xxx/xxx.git
yarn run build
git add .
git commit -m 'build'
git push -u origin master
在github上预览页面,字没出来,然后点击检查,source,发现有报错 css找不到,原因是我们没有配置路径
在package.json里加一行:"homepage": "https://x'x'x.github.io/TodoList/build"
然后接着
yarn run build
git add .
gt commit -m 'build*3'
git push
等两分钟github部署结束之后刷新预览链接,发现成功了。