React 是什么
React 是构建 UI 组件的 JS 库,专注于做 mvc 中的 v。
为什么使用React
- api 少, 类库易学
- 组件内聚,易于组合
- 原生组件和自定义组件融合
- 状态/属性驱动全局更新
- commonjs 生态圈/工具链完善
JSX
类似 xml 的语言,用来描述组件树
<div className = "x">
<a href="#">#</a>
<component x="y">...</component>
</div>
React.createElement('div', {
className: 'x'},[
React.createElement('a', {href:'#'}, '#'),
React.createElement(Component, {x: 'y'}, 1),
]
);
注意和 html 语法不太一样,必须是驼峰命名,以及属性名不能和 js 关键字冲突,例如: className, readOnly
可以通过 {变量名} 来将变量的值作为属性值
可以通过 {…obj} 来批量设置一个对象的键值对到组件的属性,注意顺序
var x = 'http://www.alipay.com';
var obj = {
href:"http://www.taobao.com",
target:"_blank"
}
var y = <a {...obj} href={x}>alipay.com</a>
React.render(y, document.getElmentById('container'));
最简单的 react 组件
Hello World Demo
<html>
<head>
<meta content="text/html;charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class HelloMessage extends React.Component {
constructor(props) {
super(props);
this.state = {name: ''};
}
render() {
return (
<div>Hello {this.props.name}!</div>
);
}
}
ReactDOM.render(
<HelloMessage name="Word"/>,
document.getElementById('container')
);
</script>
</body>
</html>
用状态控制组件变化
定时器 Demo
可以把一个组件看作一个状态机,每一次状态对应于组件的一个 UI
<html>
<head>
<meta content="text/html;charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = {
secondsElapsed: 0
};
}
tick() {
this.setState({
secondsElapsed: this.state.secondsElapsed + 1
});
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div>Seconds Elapsed: {this.state.secondsElapsed}</div>
);
}
}
ReactDOM.render(
<Timer />,
document.getElementById('container')
);
</script>
</body>
</html>
Event
可以通过设置原生 DOM 组件的 onEventType 属性来监听 DOM 事件,例如 onClick, onMouseDown, 在加强组件内聚性的同时,避免了传统 html 的全局变量污染
组合
可以像使用原生 DOM 组件一样使用自定义的组件
var A = React.createClass({
render(){
return <a href='#'>a</a>
}
});
var B = React.createClass({
render() {
return <i> <A />! </i>
}
});
React.render(<B />, document.getElementById('container'));
组合Children
var B = React.createClass({
render(){
return <ul>
{ React.Children.map(this.props.children, function(c)){
return <li>{C}</li>
}
}
</ul>
}
});
React.render(
<B>
<a href="#">1</a>
2
</B>,
document.getElementById('container'));
)
props
通过 this.props 可以获取传递给该组件的属性值,还可以通过定义 getDefaultProps 来指定默认属性值
var B = React.createClass({
getDefaultProps(){
return {
title: 'default'
};
},
render() {
return <b>{this.props.title}</b>
}
});
React.render(
<div>
<B title="指定"></B>
</div>, docuemnt.getElementById('container');
)
prop validation
通过指定 propTypes 可以校验属性的类型
var B = React.createClass({
propTypes: {
title: React.PropTypes.string,
},
render() {
retrun <b>{this.props.title}</b>
}
})
state
组件内部的状态,可以使用 state
class Hello extends Component{
constructor(props){
super(props);
this.state= {
name:"hello world"
}
}
render() {
return (
<div>{this.state.name}</div>
)
}
}
Mixin
Mixin 是一个普通对象,通过 mixin 可以在不同组件间共享代码
var A = React.createClass
Form
和 html 的不同点
- value/checked 属性设置后,用户输入无效
- textarea 的值要设置在 value 属性
- select 的 value 属性可以是数组,不建议使用 option 的 selected 属性
- input/textarea 的 onChange 用户每次输入都会触发(即使不失去焦点)
- redio/checkbox 点击后触发 onChange
如果设置了 value 属性,那么该组件变为受控组件,用户无法输入,除非程序改变 value 属性。可以通过监听 onChange 事件结合 state 来改变 input 的值
Ref
该功能是为了结合现有非 react 类库,通过 ref/refs 可以取得组件实例,进而取得原生节点
Component API
React.createClass 定义组件时允许传入的配置
- getDefaultProps 得到默认属性对象
- propTypes 属性检测规则
- mixins 组件间公用方法
Component lifecycle
React.createClass 定义时允许传入的函数,会在特定生命周期内调用
初次创建组件时调用
- getInitialState 得到初始状态对象
- render 返回组件树,必须设置
- componentDidMount 渲染到 dom 树中时调用,只在客户端调用,可用于获取原生节点
组件属性值改变时调用
- componentWillReceiveProps 属性改变调用
- shouldComponentUpdate 判断是否需要重新渲染
- render 返回组件树,必须设置
- componentDidUpdate 渲染到 dom 树中时调用,可用于获取原生节点
- 最后是 componentWillUnmount 组件,从 dom 销毁前调用
一步步搭建 React 应用
<html>
<head>
<meta content="text/html;charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class Comment extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h2>{this.props.author}</h2>
{this.props.text}
</div>
);
}
}
class CommentList extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
this.props.data.map((item, index)=> (
<Comment key ={index} author={item.author} text={item.text}></Comment>
))
);
}
}
class CommentForm extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div>
作者:<input type="text" value={this.state.author} onChange={this.props.handleAuthorOnchange}/>
评论:<input type="text" value={this.state.text} onChange={this.props.handleTextOnchange}/>
<input type="button" value="提交" onClick={this.props.handleOnClick}/>
</div>
);
}
}
class CommentBox extends React.Component {
constructor(props) {
super(props);
this.state = {
author: '作者',
text: '评论',
data: [
{author: "作者1", text: "评论1"},
{author: "作者2", text: "评论2"}
]
};
this.handleAuthorOnchange = this.handleAuthorOnchange.bind(this);
this.handleTextOnchange = this.handleTextOnchange.bind(this);
this.handleOnClick = this.handleOnClick.bind(this);
}
handleAuthorOnchange(event) {
const author = event.target.value;
this.setState({ author: author });
}
handleTextOnchange(event) {
const text = event.target.value;
this.setState({ text: text });
}
handleOnClick() {
console.log("1111");
const author = this.state.author;
const text = this.state.text;
console.log("author: " + author + ", text: " + text);
this.setState(prevState => ({
data: [...prevState.data, {author:author, text:text}]
}));
}
render() {
return (
<div>
<h1>Coments</h1>
<CommentList data={this.state.data} />
<CommentForm handleOnClick={this.handleOnClick}
handleAuthorOnchange={this.handleAuthorOnchange} handleTextOnchange={this.handleTextOnchange}/>
</div>
);
}
}
ReactDOM.render(
<CommentBox />,
document.getElementById('container')
);
</script>
</body>
</html>