本博客实现React官网首页上展示的demo, 为了方便直接采用单文件的形式, 如果想完整集成
在自己的项目中, 可以参考React官网的安装指南, 安装Create React App.
hello-world
请移步至我写的这篇博客: 单文件快速体验使用react输出hello_world
A Stateful Component
React组件除了通过this.props
传入参数, 还在内部维护this.state
, 该数据只能在组件
才能访问. 一旦组件的this.state
发生改变, React将通过调用render()
重新渲染该组件.
下面的实例, 演示了利用React.Component API的事件绑定, 实现一个简单的计数器.
完整代码如下:
<!-- filename: a-stateful-component.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>A Stateful Component</title>
<script src="https://unpkg.com/react@15.6.1/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.min.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class Timer extends React.Component {
constructor(props) {
super(props); // ES特性
this.state = {secondsElapsed: 0}; // elapse 流逝
}
tick() {
this.setState(
(prevState) => ({
secondsElapsed: prevState.secondsElapsed + 1
})
);
// 要根据以前的state值, 改变现在的state值, 需要使用函数, 上面函数
// 的参数prevSate不是固定, 可以换成任意其它名称.
// 传入的参数不管叫什么名称, 都将自动成为指向以前state的引用
}
componentDidMount() {
// 这个事件将会在React成功渲染Timer组件时, 被触发
// 其为React.Component提供的API, 名称为固定写法
this.interval = setInterval(() => this.tick(), 1000);
// 这里必须使用箭头函数, 直接使用this.tick, 将发生
// 找不到this的情况
}
componentWillUnmount() {
// 这个事件将会在Timer组件被从页面移除时被触发
// 其为React.Component提供的API, 名称为固定写法
clearInterval(this.interval);
}
render() {
return (
<div>时间流逝: {this.state.secondsElapsed}</div>
);
}
}
ReactDOM.render(<Timer />, document.getElementById('root'));
</script>
</body>
</html>
运行分析:
- 执行
Timer
组件的render()
函数进行页面渲染, 随后执行constructor
构造函数. - 页面渲染完毕后执行
componentDidMount()
.
An Application
利用state
和props
, 实现一个TodoList的小应用.
完整代码如下:
<!-- filename: an-application.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World</title>
<script src="https://unpkg.com/react@15.6.1/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.min.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class TodoApp extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this); // this绑定, 标配
this.handleChange = this.handleChange.bind(this); // this绑定, 标配
this.state = {items: [], text: ''};
}
render() {
return (
<div>
<h3>TODO APP</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input value={this.state.text} onChange={this.handleChange} />
<button>增加第 {this.state.items.length + 1} 项</button>
<p>单击button, 就意味着表单被提交</p>
</form>
</div>
);
}
handleChange(e) {
this.setState({
text: e.target.value
});
}
handleSubmit(e) {
e.preventDefault();
var newItem = {
text: this.state.text,
id: Date.now()
// 获取当前时间作为list key
// 这是react推荐用法
};
this.setState(
(prevState) => ({
items: prevState.items.concat(newItem),
text: '' // 单击提交, 就把当前输入框清空
})
);
// console.log(this.state);
}
}
class TodoList extends React.Component {
render() {
return (
<ul>
{this.props.items.map(
item =>
<li key={item.id}>{item.text}</li>
)}
</ul>
);
}
}
ReactDOM.render(
<TodoApp />,
document.getElementById('root')
);
</script>
</body>
</html>
代码运行分析:
- 当我们编辑输入框时, 实时的把录入内容, 同步到
this.sate.text
. 为此我们为输入框,
绑定onChange
事件. 输入框的value
始终和this.sate.text
保持同步. - 当我们单击提交按钮时, 我们把当前输入框的值, 追加到
this.state.items
中, 为此,
我们为提交按钮绑定onSubmit
事件. - 我们把用户输入的内容数组, 也就是
this.state.items
数组, 作为参数, 传给子组件TodoList
,
也就是给TodoList
加items={this.state.items}
属性, 我们在子组件里this.props.items
,
拿到从父组件里得到的用户输入数组, 使用map
循环遍历, 并输出.