JSX语法:
1.ReactDOM.render:用于将模板转换为HTML语言,并插入指定的DOM节点;
语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析,HTML 语言直接写在 JavaScript 语言之中,不加任何引号
1<div id="example"></div> 2 <script type="text/babel"> 3 ReactDOM.render( 4 <h1>Hello, world!</h1>, 5 document.getElementById('example') 6 ); 7 </script>
2. 它允许 HTML 与 JavaScript 的混写
语法规则:遇到代码块(以 { 开头),就用 JavaScript 规则解析
1var names = ['Alice', 'Emily', 'Kate']; 2 3 ReactDOM.render( 4 <div> 5 { 6 names.map(function (name) { 7 return <div>Hello, {name}!</div> 8 }) 9 } 10 </div>, 11 document.getElementById('example') 12 ); 13 14结果为:hello Alice hello Emily hello Kate
3.直接在模板插入 JavaScript 变量,如果这个变量是一个数组,则会展开这个数组的所有成员
1var arr = [ 2 <h1>Hello world!</h1>, 3 <h2>React is awesome</h2>, 4 ]; 5 ReactDOM.render( 6 <div>{arr}</div>, 7 document.getElementById('example') 8 ); 9结果:Hello wold! React is awesome
**二、组件:**React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件
1.React.createClass用于生成一个组件类,所有组件类都必须有自己的 render 方法,用于输出组件
语法规则:
1)组件类的第一个字母必须大写,否则会报错:如HelloMessage写成helloMessage就会报错(例1)
2)组件类只能包含一个顶层标签(例2)
例1:
1var HelloMessage = React.createClass({ 2 render: function() { 3 return <h1>Hello {this.props.name}</h1>; 4 } 5 }); 6 7 ReactDOM.render( 8 <HelloMessage name="John" />, 9 document.getElementById('example') 10 ); 11
变量 HelloMessage 就是一个组件类,<HelloMessage /> 会自动生成 HelloMessage 的一个实例
例2:
1var HelloMessage = React.createClass({ 2 render: function() { 3 return <h1> 4 Hello {this.props.name} 5 </h1><p> 6 some text 7 </p>; 8 } 9 });
这种写法就会报错:因为有两个顶层标签h1和p
3.给组件添加自定义属性:
语法规则:
1)为组件HelloMessage添加一个name属性
2)在组件类中使用this.props对象获取属性值
3)因为class和for是js的保留字,所以 clss需要写成:className,for需要写成:htmlFor
1var HelloMessage = React.createClass({ 2 render: function() { 3 return <h1>Hello {this.props.name}</h1>; 4 } 5 }); 6 7 ReactDOM.render( 8 <HelloMessage name="John" />, 9 document.getElementById('example') 10 );
**三、this.props.children属性:**表示组件的所有子节点
1var NotesList = React.createClass({ 2 render: function() { 3 return ( 4 <ol> 5 { 6 React.Children.map(this.props.children, function (child) { 7 return <li>{child}</li>; 8 }) 9 } 10 </ol> 11 ); 12 } 13 }); 14 15 ReactDOM.render( 16 <NotesList> 17 <span>hello</span> 18 <span>world</span> 19 </NotesList>, 20 document.body 21 );结果:1.hello 2.world
以上为: 通过this.props.children来读取NodeList组件的两个子节点span
注意1:this.props.children有三种可能值:
1)没有子节点时:undefined
2) 一个子节点时:Object
3) 多个子节点时:Array
注意2:可以使用React.Children.map来遍历子节点(更多方法官方文档)
**四、PropTypes属性:**就是用来验证组件实例的属性是否符合要求
注:组件的属性可以接受任意值,字符串、对象、函数等等都可以
1var MyTitle = React.createClass({ 2 propTypes: { 3 title: React.PropTypes.string.isRequired, 4 }, 5 6 render: function() { 7 return <h1> {this.props.title} </h1>; 8 } 9 });
PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。现在,我们设置 title 属性的值是一个数值就会报错。更多的PropTypes设置看官网
五、getDefaultProps方法:可以用来设置组件属性的默认方法
1var MyTitle = React.createClass({ 2 getDefaultProps : function () { 3 return { 4 title : 'Hello World' 5 }; 6 }, 7 8 render: function() { 9 return <h1> {this.props.title} </h1>; 10 } 11}); 12 13ReactDOM.render( 14 <MyTitle />, 15 document.body 16);结果:Hello World
六、获取真实的DOM节点:
组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。
但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性。
1var MyComponent = React.createClass({ 2 handleClick: function() { 3 this.refs.myTextInput.focus(); 4 }, 5 render: function() { 6 return ( 7 <div> 8 <input type="text" ref="myTextInput" /> 9 <input type="button" value="Focus the text input" onClick={this.handleClick} /> 10 </div> 11 ); 12 } 13 }); 14 15 ReactDOM.render( 16 <MyComponent />, 17 document.getElementById('example') 18 );
上面代码中,组件 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
1var LikeButton = React.createClass({ 2 getInitialState: function() { 3 return {liked: false}; 4 }, 5 handleClick: function(event) { 6 this.setState({liked: !this.state.liked}); 7 }, 8 render: function() { 9 var text = this.state.liked ? 'like' : 'haven\'t liked'; 10 return ( 11 <p onClick={this.handleClick}> 12 You {text} this. Click to toggle. 13 </p> 14 ); 15 } 16 }); 17 18 ReactDOM.render( 19 <LikeButton />, 20 document.getElementById('example') 21 );
getInitialState:方法用于定义初始状态,也就是一个对象。
this.state:读取getInitialState返回的状态值 如:liked:false。
this.setState:修改状态值,每次修改以后自动调用this.render方法,在此渲染组件。
this.pros和this.setState的区别:
1)this.props:用于一旦定义就不再改变的特性;
2)this.setState:随着用户互动而产生变化的特性
**九、表单:**用户再表单输入的内容,属于用户跟组件互动,所以不能用this.props读取
1var Input = React.createClass({ 2 getInitialState: function() { 3 return {value: 'Hello!'}; 4 }, 5 handleChange: function(event) { 6 this.setState({value: event.target.value}); 7 }, 8 render: function () { 9 var value = this.state.value; 10 return ( 11 <div> 12 <input type="text" value={value} onChange={this.handleChange} /> 13 <p>{value}</p> 14 </div> 15 ); 16 } 17 }); 18 19 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):组件判断是否重新渲染时调用
1var Hello = React.createClass({ 2 getInitialState: function () { 3 return { 4 opacity: 1.0 5 }; 6 }, 7 8 componentDidMount: function () { 9 this.timer = setInterval(function () { 10 var opacity = this.state.opacity; 11 opacity -= .05; 12 if (opacity < 0.1) { 13 opacity = 1.0; 14 } 15 this.setState({ 16 opacity: opacity 17 }); 18 }.bind(this), 100); 19 }, 20 21 render: function () { 22 return ( 23 <div style={{opacity: this.state.opacity}}> 24 Hello {this.props.name} 25 </div> 26 ); 27 } 28}); 29 30ReactDOM.render( 31 <Hello name="world"/>, 32 document.body 33);
注意:1)style的格式:style={{opacity: this.state.opacity}}
- 注意setinterval()方法中,回调函数一定要加.bind(this)方法,原因是:在setInterval()中定义的回调函数,是在同步代码执行完后,随着事件触发来异步执行的,此时函数的上下文Context已经由定义该函数的Script文件变为全局变量,如果不通过bind(this)来指定由组件实例作为上下文的话,回调函数中的this会指向全局变量中的Window变量,显然不是我们想要的结果。
十一、Ajax
组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI
1var UserGist = React.createClass({ 2 getInitialState: function() { 3 return { 4 username: '', 5 lastGistUrl: '' 6 }; 7 }, 8 9 componentDidMount: function() { 10 $.get(this.props.source, function(result) { 11 var lastGist = result[0]; 12 if (this.isMounted()) { 13 this.setState({ 14 username: lastGist.owner.login, 15 lastGistUrl: lastGist.html_url 16 }); 17 } 18 }.bind(this)); 19 }, 20 21 render: function() { 22 return ( 23 <div> 24 {this.state.username}'s last gist is 25 <a href={this.state.lastGistUrl}>here</a>. 26 </div> 27 ); 28 } 29 }); 30 31 ReactDOM.render( 32 <UserGist source="https://api.github.com/users/octocat/gists" />, 33 document.body 34 );
我们甚至可以把一个Promise对象传入组件
1var RepoList = React.createClass({ 2 getInitialState: function() { 3 return { loading: true, error: null, data: null}; 4 }, 5 6 componentDidMount() { 7 this.props.promise.then( 8 value => this.setState({loading: false, data: value}), 9 error => this.setState({loading: false, error: error})); 10 }, 11 12 render: function() { 13 if (this.state.loading) { 14 return <span>Loading...</span>; 15 } 16 else if (this.state.error !== null) { 17 return <span>Error: {this.state.error.message}</span>; 18 } 19 else { 20 var repos = this.state.data.items; 21 var repoList = repos.map(function (repo) { 22 return ( 23 <li> 24 <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description} 25 </li> 26 ); 27 }); 28 return ( 29 <main> 30 <h1>Most Popular JavaScript Projects in Github</h1> 31 <ol>{repoList}</ol> 32 </main> 33 ); 34 } 35 } 36 }); 37 38 39ReactDOM.render( 40 <RepoList 41 promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')} 42 />, 43 document.body 44);
如果Promise对象正在抓取数据(pending状态),组件显示"正在加载";如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据