1、组件的组合
案例效果
- 显示所有 todo 列表
- 输入文本, 点击按钮显示到列表的首位, 并清除输入的文本
功能界面的组件化编码流程(无比重要)
- 拆分组件: 拆分界面,抽取组件
- 实现静态组件: 使用组件实现静态页面效果
- 实现动态组件
a. 动态显示初始化数据
b. 交互功能(从绑定事件监听开始)
源代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>05_components_composing</title>
</head>
<body>
<div id="example"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
class App extends React.Component{
constructor(props){
super(props)
this.state = {
todos:['喜欢','吃饭','打代码']
}
this.addTodo = this.addTodo.bind(this)
}
addTodo (todo){
const {todos}=this.state
todos.unshift(todo)
this.setState({todos})
}
render(){
const {todos} = this.state
return(
<div>
<h1>Simple TODO List</h1>
<Add count={todos.length} addTodo={this.addTodo}/>
<List todos={todos} />
</div>
)
}
}
class Add extends React.Component{
constructor(props){
super(props)
this.handleAdd=this.handleAdd.bind(this)
}
handleAdd() {
//1.读取输入数据
const todo = this.todoInput.value.trim()
//2.检查合法性
if (!todo) {
return
}
//3.添加
this.props.addTodo(todo)
//清楚输框的内容
this.todoInput.value = ''
}
render(){
return(
<div>
<input type="text" ref={input => this.todoInput=input}/>
<button onClick={this.handleAdd}>add #{this.props.count+1}</button>
</div>
)
}
}
Add.propTypes ={
count:PropTypes.number.isRequired,
addTodo:PropTypes.func.isRequired
}
class List extends React.Component{
render(){
const {todos} = this.props
return(
<ul>
{
this.props.todos.map((todo,index) =>
<li key={index}>{todo}</li>)
}
</ul>
)
}
}
List.propTypes ={
todos:PropTypes.array.isRequired
}
//渲染组件标签 只渲染父组件
ReactDOM.render(<App />,document.getElementById('example'))
</script>
</body>
</html>
运行效果

编写代码时思考的问题
- 问题1:数据应保存在哪个组件内?十分重要
- 看是某个组件需要还是某些,若某个则给单个组件 若是某些组件都需要则给共同的
父组件。此案例放在APP里,因为两个子组件都需要用到该数据。
- 问题2:需要在子组件改变父组件的状态 (子组件不能直接改变父组件状态)
- 状态在哪个组件,更新状态的行为就应定义在哪个组件。
- 解决方案:父组件定义函数,传递给子组件,子组件调用
组件化编写功能的流程
- 注意:要理清逻辑编写代码。在父子组件中存入Add 和List子组件都需要用的输入的数据。
- App父组件定义
addTodo
函数,传递给Add子组件<Add count={todos.length} addTodo={this.addTodo}/>
,以便于之后子组件调用。List组件同理。
- Add子组件通过
<input type="text" ref={input => this.todoInput=input}/>
(非受控组件接受数据)
并且通过<button onClick={this.handleAdd}>add #{this.props.count+1}</button>
事件处理,来调用handleAdd
函数,进而调用父组件的addTodo
函数。
- List子组件内通过
this.props.todos.map((todo,index) => <li key={index}>{todo}</li>)
生成一个新的数组,来返回列表。
2、收集表单数据
案例效果
- 输入用户名密码后, 点击登陆提示输入信息
- 不提交表单
理解
- 问题: 在 react 应用中, 如何收集表单输入数据
- 包含表单的组件分类
a. 受控组件: 表单项输入数据能自动收集成状态
b. 非受控组件: 需要时才手动读取表单输入框中的数据
源代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>09_form</title>
</head>
<body>
<div id="example"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
/*
需求: 自定义包含表单的组件
1. 界面如下所示
2. 输入用户名密码后, 点击登陆提示输入信息
3. 不提交表单
*/
class LoginForm extends React.Component{
constructor(props){
super(props)
this.state = {
pwd:''
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleSubmit(event){
//1.不让表单提交,阻止默认行为(由于表单有默认的提交功能)
event.preventDefault()
//2.将数据读出
const name = this.nameInput.value
const {pwd} = this.state
//const password = this.pwInput.value
//3.弹出数据
//alert('输入的用户名为${name},密码为${pwd}')
alert("用户名:"+name+"\n密码:"+ pwd)
}
handleChange(event){
//读取输入数据
const pwd = event.target.value
//更新pwd状态
this.setState({pwd})
}
render(){
return(
<form action="/text" onSubmit={this.handleSubmit}>
用户名:<input type="text" ref={input => this.nameInput = input}/>
密码:<input type="password" value={this.state.pwd} onChange={this.handleChange}/>
<input type="submit" value="登陆"/>
</form>
)
}
}
ReactDOM.render(<LoginForm/>,document.getElementById('example'))
</script>
</body>
</html>
运行效果


编写代码时思考问题
- 1.不让表单提交,阻止默认行为(由于表单有默认的提交功能)
event.preventDefault()
- 此案例,读取用户名和密码时,用户名用的是非受控组件,密码用的是受控组件
-
用户名:<input type="text" ref={input => this.nameInput =input}/>
密码:<input type="password" value={this.state.pwd} onChange{this.handleChange}/>