React在ES6中的用法
阿新 • • 發佈:2019-02-16
寫在前面
不管是多麼不樂意待見這個不速之客,但ES6已經一點點滲透進了我的生活裡,就連我最愛的React到React Native,預設都把ES6做為首選標準。這是FaceBook有計劃、有聲勢地要把ES6推起來,請問還有誰有狗膽站住來堵著路不走。所以我毅然捧著阮一峰老師的《ES6標準入門》在一旁看了起來……那好,今天就談談如何把React用ES6愉快地跑起來。
入門級Demos
先來幾個簡單的demo體驗一把。注意,例子裡ES5的require請通過browserfiy或webpack來實現,如果你還不會用這兩樣東西,請出門後往前看。
“Hello,XXX”輸出
ES5寫法:
var React = require('react');
var HelloMessage = React.createClass({
render: function() {
return (<h1>Hello,{this.props.name}!</h1>);
}
});
module.exports = React.createClass({
render: function() {
return (
<div>
<HelloMessage name = "John" />
</div>
);
}
});
ES6寫法:
import React,{Component} from 'react';
class HelloMessage extends Component{
constructor() {
super();
}
render(){
return <h1>Hello {this.props.name}</h1>;
}
}
class Output extends Component{
constructor() {
super ();
}
render(){
return (
<div>
<HelloMessage name="John" />
</div>
);
}
}
export default Output;
陣列遍歷顯示
ES5寫法:
var React = require('react');
var RepeatArray = React.createClass({
render: function() {
var names = ['Alice', 'Emily', 'Kate'];
var arrs = [
<h1>Hello World</h1>,
<h2>React is awesome</h2>
];
return (
<div>
{arr}
{
names.map(function (name) {return <div>Hello, {name}!</div>;});
}
</div>
);
}
});
module.exports = RepeatArray;
ES6寫法:
import React,{Component} from 'react';
class RepeatArray extends Component{
constructor() {
super();
}
render(){
var arr = [
<h1>Hello world!</h1>,
<h2>React is awesome</h2>,
];
var names = ['Alice', 'Emily', 'Kate'];
return (
<div>
{arr}
{
names.map((name) =>{return <div>Hello, {name}!</div>;} )
}
</div>
);
}
}
export default RepeatArray;
ol與li的實現
ES5寫法:
var React = require('react');
var RepeatLi = React.createClass({
render: function() {
return(
<ol>
{
this.props.children.map(function(child) {
return <li>{child}</li>;
});
}
</ol>
);
}
});
module.exports = React.createClass({
render: function() {
return (
<div>
<RepeatLi>
<span>hello</span>
<span>world</span>
</RepeatLi>
</div>
);
}
});
ES6寫法:
import React,{Component} from 'react';
class RepeatLi extends Component{
render(){
return (
<ol>
{
this.props.children.map((child)=>{return <li>{child}</li>})
}
</ol>
);
}
}
class RepeatArray extends Component{
constructor() {
super();
}
render(){
return (
<div>
<RepeatLi>
<span>hello</span>
<span>world</span>
</RepeatLi>
</div>
);
}
}
export default RepeatArray;
Click事件
ES5寫法:
var React = require('react');
var MyComponent = React.createClass({
handleClick: function() {
React.findDOMNode(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>
);
}
});
module.exports = React.createClass({
render: function() {
return (
<div>
<MyComponent />
</div>
);
}
});
ES6寫法:
import React,{Component} from 'react';
class FocusText extends Component{
handleClick(){
React.findDOMNode(this.refs.myText).focus();
}
render(){
return(
<div>
<input type="text" ref="myText" />
<input type="button" value="focus the text input" onClick={this.handleClick.bind(this)} />
</div>
);
}
}
class RepeatArray extends Component{
constructor() {
super();
}
render(){
return (
<div>
<FocusText />
</div>
);
}
}
export default RepeatArray;
State的用法,以toggel顯示文字為例
ES5寫法:
var React = require('react');
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(e) {
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>
);
}
});
module.exports = React.createClass({
render: function() {
return (<div><LikeButton /></div>);
}
});
ES6寫法:
import React,{Component} from 'react';
class StateUse extends Component{
constructor(){
super();
this.state={
like:true
}
}
handleClick(){
this.setState({like:!this.state.like});
}
render(){
var text = this.state.like?'Like':"Unlike";
return(
<div>
<p onClick={this.handleClick.bind(this)}>
You {text} this.Click the toggle;
</p>
</div>
);
}
}
class RepeatArray extends Component{
constructor() {
super();
}
render(){
return (
<div>
<StateUse />
</div>
);
}
}
export default RepeatArray;
onChange事件,以及變數值的同步
ES5寫法:
var React = require('react');
var InputComponent = React.createClass({
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(e) {
this.setState({value: e.target.value})
},
render: function() {
var value = this.state.value;
return (
<div>
<input type="text" value={value} onChange={this.handleChangle} />
<p>{value}</p>
</div>
);
}
});
module.exports = React.createClass({
render: function() {
return (<div><InputComponent /></div>)
}
});
ES6寫法:
import React,{Component} from 'react';
class AsyncText extends Component{
constructor(){
super();
this.state={
value:'Hello!'
}
}
handleChange(e){
this.setState({value:e.target.value});
}
render(){
var value= this.state.value;
return(
<div>
<input type="text" value={value} onChange={this.handleChange.bind(this)} />
<p>
{value}
</p>
</div>
);
}
}
class RepeatArray extends Component{
constructor() {
super();
}
render(){
return (
<AsyncText />
</div>
);
}
}
export default RepeatArray;
定時任務事件的嵌入
ES5寫法:
var React = require('react');
var Hello = React.createClass({
getInitState: 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>
);
}
});
module.exports = React.createClass({
render: function() {
return (<div><Hello name="world" /></div>);
}
});
ES6寫法:
import React,{Component} from 'react';
class OpacityWord extends Component{
constructor(){
super();
this.state={
opacity:1.0
}
}
componentWillMount(){
let time = setInterval(()=>{
let opacity = this.state.opacity;
opacity -= 0.5;
if (opacity<0.1) {
opacity=1.0;
}
this.setState({opacity:opacity});
}.bind(this),100);
}
render(){
return (
<div style={{ opacity:this.state.opacity }}>
Hello, {this.props.name}!
</div>
);
}
}
class RepeatArray extends Component{
constructor() {
super();
}
render(){
return (
<div>
<OpacityWord />
</div>
);
}
}
export default RepeatArray;
從服務端獲取資料
ES5寫法:
var React = require('react');
var UserGist = React.createClass({
getInitState: function() {
return {
username: '',
lastGistUrl: ''
};
},
componentDidMount: function() {
$.get(this.props.source, function(result) {
var lastGist = result[0];
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>
);
}
});
module.exports = React.createClass({
render: function() {
return (
<div>
<UserGist source="https://api.github.com/users/octocat/gists" />
</div>
);
}
});
ES6寫法:
import React,{Component} from 'react';
class UserGist extends Component{
constructor(){
super();
this.state={
username:'',
lastGistUrl:''
}
}
componentWillMount(){
$.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(){
return(
<div>
{this.state.username} ..
<a href={this.state.lastGistUrl} >here</a>
</div>
);
}
}
class RepeatArray extends Component{
constructor() {
super();
}
render(){
return (
<div>
<UserGist source="https://api.github.com/users/octocat/gists" />
</div>
);
}
}
export default RepeatArray;
React Native實戰
寫一個簡單的頁面,支援輸入關鍵字然後以列表形式呈現github裡搜尋出來的結果。效果如下:
ES5寫法:
'use strict';
var React = require('react-native');
var {
Image,
ListView,
TextInput,
AppRegistry,
Component,
StyleSheet,
Text,
View,
} = React;
var BASE_URL = "https://api.github.com/search/repositories?q=";
var customView = React.createClass({
getInitialState: function() {
return {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
};
},
render: function() {
if (this.state.dataSource.getRowCount() === 0) {
console.log('YES');
}
var content = this.state.dataSource.getRowCount() === 0 ?
<Text style={styles.blankText}>
Please enter a search term to see results.
</Text> :
<ListView
ref="listview"
dataSource={this.state.dataSource}
renderRow={this.renderRow}
automaticallyAdjustContentInsets={false}
keyboardDismissMode="onDrag"
keyboardShouldPersistTaps={true}
showsVerticalScrollIndicator={false} />;
return (
<View style={styles.container}>
<TextInput
autoCapitalize="none"
autoCorrect={false}
placeholder="Search for a project..."
style={styles.searchBarInput} onEndEditing={this.onSearchChange}/>
{content}
</View>
);
},
onSearchChange: function(event: Object) {
var searchTerm = event.nativeEvent.text.toLowerCase();
var queryURL = BASE_URL + encodeURIComponent(searchTerm);
fetch(queryURL)
.then((response) => response.json())
.then((responseData) => {
if (responseData.items) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.items),
});
}
}).done();
},
renderRow: function(repo: Object) {
return (
<View>
<View style={styles.row}>
<Image source={{uri: repo.owner.avatar_url}}
style={styles.profPic}/>
<View style={styles.textContainer}>
<Text style={styles.title}>
{repo.name}
</Text>
<Text style={styles.subTitle}>
{repo.owner.login}
</Text>
</View>
<View style={styles.cellBorder}></View>
</View>
</View>
);
},
});
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ffffff',
},
searchBarInput: {
marginTop: 30,
padding: 5,
fontSize: 15,
height: 30,
backgroundColor: '#EAEAEA',
},
row: {
alignItems: 'center',
backgroundColor: 'white',
flexDirection: 'row',
padding: 5,
},
cellBorder: {
backgroundColor: 'rgba(0,0,0,0.1)',
height: 1,
marginLeft: 4,
},
profPic: {
width: 50,
height: 50,
},
title: {
fontSize: 20,
marginBottom: 8,
fontWeight: 'bold',
},
subTitle: {
fontSize: 16,
marginBottom: 8,
},
textContainer: {
paddingLeft: 10,
},
blankText: {
padding: 10,
fontSize: 20,
}
});
AppRegistry.registerComponent('customView', () => customView);
ES6寫法:
import React, {
Image,
ListView,
TextInput,
AppRegistry,
Component,
StyleSheet,
Text,
View,
}
from 'react-native';
const BASE_URL = "https://api.github.com/search/repositories?q=";
class customView extends Component {
constructor() {
super();
}
state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
}
render() {
if (this.state.dataSource.getRowCount() === 0) {
console.log('YES');
}
var content = this.state.dataSource.getRowCount() === 0 ?
<Text style={styles.blankText}>
Please enter a search term to see results.
</Text> :
<ListView
ref="listview"
dataSource={this.state.dataSource}
renderRow={this.renderRow}
automaticallyAdjustContentInsets={false}
keyboardDismissMode="onDrag"
keyboardShouldPersistTaps={true}
showsVerticalScrollIndicator={false} />;
return (
<View style={styles.container}>
<TextInput
autoCapitalize="none"
autoCorrect={false}
placeholder="Search for a project..."
style={styles.searchBarInput} onEndEditing={this.onSearchChange}/>
{content}
</View>
);
}
onSearchChange(event: Object) {
var searchTerm = event.nativeEvent.text.toLowerCase();
var queryURL = BASE_URL + encodeURIComponent(searchTerm);
fetch(queryURL)
.then((response) => response.json())
.then((responseData) => {
if (responseData.items) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.items),
});
}
}).done();
}
renderRow(repo: Object) {
return (
<View>
<View style={styles.row}>
<Image source={{uri: repo.owner.avatar_url}}
style={styles.profPic}/>
<View style={styles.textContainer}>
<Text style={styles.title}>
{repo.name}
</Text>
<Text style={styles.subTitle}>
{repo.owner.login}
</Text>
</View>
<View style={styles.cellBorder}></View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ffffff',
},
searchBarInput: {
marginTop: 30,
padding: 5,
fontSize: 15,
height: 30,
backgroundColor: '#EAEAEA',
},
row: {
alignItems: 'center',
backgroundColor: 'white',
flexDirection: 'row',
padding: 5,
},
cellBorder: {
backgroundColor: 'rgba(0,0,0,0.1)',
height: 1,
marginLeft: 4,
},
profPic: {
width: 50,
height: 50,
},
title: {
fontSize: 20,
marginBottom: 8,
fontWeight: 'bold',
},
subTitle: {
fontSize: 16,
marginBottom: 8,
},
textContainer: {
paddingLeft: 10,
},
blankText: {
padding: 10,
fontSize: 20,
}
});
AppRegistry.registerComponent('customView', () => customView);