React重点概要
JSX语法:
1.ReactDOM.render:用于将模板转换为HTML语言,并插入指定的DOM节点;
语法规则:遇到 HTML 标签(以 <
开头),就用 HTML 规则解析,HTML 语言直接写在 JavaScript 语言之中,不加任何引号
<div id="example"></div> <script type="text/babel"> ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') ); </script>
2. 它允许 HTML 与 JavaScript 的混写
语法规则:遇到代码块(以 {
开头),就用 JavaScript 规则解析
var names = ['Alice', 'Emily', 'Kate']; ReactDOM.render( <div> { names.map(function (name) { return <div>Hello, {name}!</div> }) } </div>, document.getElementById('example') ); 结果为:hello Alice hello Emily hello Kate
3.直接在模板插入 JavaScript 变量,如果这个变量是一个数组,则会展开这个数组的所有成员
var arr = [ <h1>Hello world!</h1>, <h2>React is awesome</h2>, ]; ReactDOM.render( <div>{arr}</div>, document.getElementById('example') ); 结果:Hello wold! React is awesome
二、组件:React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件
1.React.createClass用于生成一个组件类,所有组件类都必须有自己的 render
方法,用于输出组件
语法规则:
1)组件类的第一个字母必须大写,否则会报错:如HelloMessage写成helloMessage就会报错(例1)
2)组件类只能包含一个顶层标签(例2)
例1:
var HelloMessage = React.createClass({ render: function() { return <h1>Hello {this.props.name}</h1>; } }); ReactDOM.render( <HelloMessage name="John" />, document.getElementById('example') );
变量 HelloMessage
就是一个组件类,<HelloMessage />
会自动生成 HelloMessage
的一个实例
例2:
var HelloMessage = React.createClass({ render: function() { return <h1> Hello {this.props.name} </h1><p> some text </p>; } });
这种写法就会报错:因为有两个顶层标签h1和p
3.给组件添加自定义属性:
语法规则:
1)为组件HelloMessage添加一个name属性
2)在组件类中使用this.props对象获取属性值
3)因为class和for是js的保留字,所以 clss需要写成:className,for需要写成:htmlFor
var HelloMessage = React.createClass({ render: function() { return <h1>Hello {this.props.name}</h1>; } }); ReactDOM.render( <HelloMessage name="John" />, document.getElementById('example') );
三、this.props.children属性:表示组件的所有子节点
var NotesList = React.createClass({ render: function() { return ( <ol> { React.Children.map(this.props.children, function (child) { return <li>{child}</li>; }) } </ol> ); } }); ReactDOM.render( <NotesList> <span>hello</span> <span>world</span> </NotesList>, document.body );
结果:1.hello 2.world
以上为: 通过this.props.children来读取NodeList组件的两个子节点span
注意1:this.props.children有三种可能值:
1)没有子节点时:undefined
2) 一个子节点时:Object
3) 多个子节点时:Array
注意2:可以使用React.Children.map来遍历子节点(更多方法官方文档)
四、PropTypes属性:就是用来验证组件实例的属性是否符合要求
注:组件的属性可以接受任意值,字符串、对象、函数等等都可以
var MyTitle = React.createClass({ propTypes: { title: React.PropTypes.string.isRequired, }, render: function() { return <h1> {this.props.title} </h1>; } });
PropTypes
告诉 React,这个 title
属性是必须的,而且它的值必须是字符串。现在,我们设置 title
属性的值是一个数值就会报错。更多的PropTypes设置看官网
五、getDefaultProps方法:
可以用来设置组件属性的默认方法
var MyTitle = React.createClass({ getDefaultProps : function () { return { title : 'Hello World' }; }, render: function() { return <h1> {this.props.title} </h1>; } }); ReactDOM.render( <MyTitle />, document.body );
结果:Hello World
六、获取真实的DOM节点:
组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 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') );
上面代码中,组件 MyComponent
的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref
属性,然后 this.refs.[refName]
就会返回这个真实的 DOM 节点。
需要注意的是,由于 this.refs.[refName]
属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click
事件的回调函数,确保了只有等到真实 DOM 发生 Click
事件之后,才会读取 this.refs.[refName]
属性。
React 组件支持很多事件,除了 Click
事件以外,还有 KeyDown
、Copy
、Scroll
等
七、this.state:将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI
var LikeButton = React.createClass({ getInitialState: function() { 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') );
getInitialState:方法用于定义初始状态,也就是一个对象。
this.state:读取getInitialState返回的状态值 如:liked:false。
this.setState:修改状态值,每次修改以后自动调用this.render方法,在此渲染组件。
this.pros和this.setState的区别:
1)this.props:用于一旦定义就不再改变的特性;
2)this.setState:随着用户互动而产生变化的特性
九、表单:用户再表单输入的内容,属于用户跟组件互动,所以不能用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);
onChange:事件的回调函数
event.target.value:读取用户输入的值
注:像textarea、select、redio都属于这种情况
十:组件的声明周期:
1.组件的生命周期分为三个状态:
Mounting:以插入真实DOM
Updating:正在被重新渲染
Unmounting:已移除真实DOM
2.React为每个状态都提供了两种处理函数:
wil:函数正在进入状态之前调用
did:函数在进入状态之后调用
3.三种状态共计五种处理函数:
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps,object nextState)
componentDidUpdate(object prevProps,object prevState)
componentWillUnmount()
4.特殊状态:
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nectProps,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}}> Hello {this.props.name} </div> ); } }); ReactDOM.render( <Hello name="world"/>, document.body );
注意:1)style的格式:style={{opacity: this.state.opacity}}
2) 注意setinterval()方法中,回调函数一定要加.bind(this)方法,原因是:在setInterval()中定义的回调函数,是在同步代码执行完后,随着事件触发来异步执行的,此时函数的上下文Context已经由定义该函数的Script文件变为全局变量,如果不通过bind(this)来指定由组件实例作为上下文的话,回调函数中的this会指向全局变量中的Window变量,显然不是我们想要的结果。
十一、Ajax
组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount
方法设置 Ajax 请求,等到请求成功,再用 this.setState
方法重新渲染 UI
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 );
我们甚至可以把一个Promise对象传入组件
var RepoList = React.createClass({ getInitialState: function() { return { loading: true, error: null, data: null}; }, componentDidMount() { this.props.promise.then( value => this.setState({loading: false, data: value}), error => this.setState({loading: false, error: error})); }, 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 { var repos = this.state.data.items; var repoList = repos.map(function (repo) { return ( <li> <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description} </li> ); }); return ( <main> <h1>Most Popular JavaScript Projects in Github</h1> <ol>{repoList}</ol> </main> ); } } }); ReactDOM.render( <RepoList promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')} />, document.body );
如果Promise对象正在抓取数据(pending状态),组件显示"正在加载";如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据