已经有vue 框架使用经验的人知道,真实的项目开发中,组件封装,嵌套,传值等都非常重要,想必使用React 框架开发项目,也一定不是只是用一个组件就够了,所以这篇文章梳理React 组件组合使用基础。
基本理解
我们知道,页面要有一个根组件,其他的封装的组件则要嵌套在根组件或者其应该在得父组件中,组件的组合使用,就是会有组件的嵌套使用,涉及到传值,数据处理等。
TODO List 案例
效果
通过一个小案例来具体了解下 组件组合使用的基本实现,最终的实现页面图如下
需求
- 显示所有 todo 列表
- 输入文本,点击按钮输入内容显示到todo 列表的首位,输入框数据同时清空
案例分析
Q:整个页面需要抽取出多少组件比较合适
A: 看功能边界,首先页面要有根组件,通常是命名为app, 有一个添加todo 的组件 Add , 有显示todo 的列表组件List
Q: 拆分完了,从哪开始写
A:先写静态页面,再实现动态组件
Q:静态页面好说,动态的组件如何下手
A:动态组件的实现 首先是动态渲染初始化数据,然后处理交互逻辑,交互逻辑一般从绑定的事件监听开始
Q:从页面需求我能分析出需要哪些数据,比如需要todo的列表数据 todos ,那么这个数据我应该放在那个组件的状态里呢
A:数据放在哪个组件state 中,要分析数据在哪用,如果只在本组件中用,那放在本组件中就行,如果除了本组件,其他组件也要用,要放在他们共同的父组件中,注意此处的父组件不是继承关系的组件,而是标签意义上的父组件。
Q:具体分析结果是什么
A:首先我们知道数据一定有todo 的列表数据,那么这个列表数据哪里用呢,List 列表组件要用,因为要读取后渲染到列表页,那么添加组件要不要,当然也要,新增的todo 要通过Add 组件更新todos 列表。
Q:数据封装在App 组件中,那么Add 组件肯定会需要更新数据App中数据的状态,怎么办?
A:React 组件更新状态规定,状态定义在哪个组件,更新状态的行为就应该定义在哪个组件?
Q: 子组件怎么使用呢?
A:父组件定义函数,传递给子组件,子组件调用。
这样分析一遍是不是解决了大部分一问,可以从拆分组件 定义静态组件,动态渲染初始化数据,交互从监听开始。
小案例完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件组合使用</title>
</head>
<body>
<div id="example"></div>
<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.bootcdn.net/ajax/libs/prop-types/15.7.2/prop-types.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
/*
功能需求
1、显示所有todo 列表
2、输入文本,点击按钮显示到列表的首位,并清除输入的文本
*/
// 定义组件
class App extends React.Component{
constructor(props){
super(props)
this.state ={
todos:['吃饭','睡觉','学习']
}
this.addTodo = this.addTodo.bind(this)
}
addTodo(todo){
console.log(this.state)
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.add = this.add.bind(this)
}
add(){
// 将输入的数据添加到todos 里取
// 涉及需要在子组件中改变父组件的状态 但是子组件不能直接更新父组件的状态
// 装填在哪个组件 ,更新状态的行为就应该在哪个组件。父组件封装了方法,子组件中需要调用这个方法
// 可以从父组件将封装好的函数 传递给子组件
// 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" placeholder='请输入' ref={input=>this.todoInput=input}/>
<button onClick={this.add}> add # {this.props.count+1}</button>
</div>
)
}
}
Add.propTypes = {
count:PropTypes.number.isRequired,
addTodo:PropTypes.func.isRequired
}
class List extends React.Component{
render(){
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>
注意事项及总结
注意事项
根据分析思路去敲代码的时候要注意,todos列表数据封装在App 根组件中,那么里面的两个字组件传值直接属性传值到props 中就可以,但是至于state中数据的更新,要遵循 数据在哪个组件就在哪个组件更新,在父组件中封装更新数据的方法,以属性参数的形式传给子组件使用,这个问题在上面的问答分析中已经包含,还是要重点关注一下。
总结
功能界面 组件化编码的流程(重要)
- 拆分组件 : 拆分界面,抽取组件
- 实现静态组件:使用组件实现静态页面效果
- 实现动态组件
- ① 动态显示初始化数据
- ②交互功能(从绑定事件监听开始)
关于组件的组合使用,能把todo 小demo 练习写出来,就算入门了,因为有Vue 基础,理解起来比较简单。