例子来自尚硅谷react视频,相当于笔记整理
link: https://www.bilibili.com/video/av51174155?from=search&seid=11218837597275325699
要做的功能: 在输入框内输入内容,点击add按钮自动添加到下面的列表去,并且清空input
重点是通过这个例子,把如何进行解决react多组件的创建和交互的思路理清了。
功能界面组件化编码流程:
1 拆分组件:拆分页面,抽取组件
2 实现静态组件: 使用组件实现静态页面效果
3 实现动态组件:
1)动态显示初始化数据
2)交互功能(从绑定事件监听开始)
问题:数据保存在哪个组件内?
解答:看数据是某个组件需要还是某些组件需要。
如果是后者,要将数据给共同的父组件。
问题:如何做交互?
解答:先绑定监听
问题:如何在子组件中改变父组件状态?
解答:子组件中不能直接改变父组件状态。状态在哪个组件,更新状态的行为就应该定义在哪个组件。
在本例中,父组件中定义更新状态的方法,子组件使用该方法,因此需要将该方法从父组件传递到子组件中。方式是通过props来传递。
精简地说:父组件定义函数,传递给子组件,子组件调用
/*
功能界面组件化编码流程:
1 拆分组件:拆分页面,抽取组件
2 实现静态组件: 使用组件实现静态页面效果
3 实现动态组件:
1)动态显示初始化数据
2)交互功能(从绑定事件监听开始)
问题:数据保存在哪个组件内?
解答:看数据是某个组件需要还是某些组件需要。
如果是后者,要将数据给共同的父组件。
问题:如何做交互?
解答:先绑定监听
问题:如何在子组件中改变父组件状态?
解答:子组件中不能直接改变父组件状态。状态在哪个组件,更新状态的行为就应该定义在哪个组件。
在本例中,父组件中定义更新状态的方法,子组件使用该方法,因此需要将该方法从父组件传递到子组件中。方式是通过props来传递。
精简地说:父组件定义函数,传递给子组件,子组件调用
*/
class App extends React.Component{
constructor(props){
super(props);
this.state = {
todos: ['Read', 'Write']
}
this.addTodo = this.addTodo.bind(this);
}
addTodo (todo){
console.log('addTodo - App')
const {todos} = this.state
todos.unshift(todo)
this.setState({todos}) //必须调用setState才会更新页面
console.log(todos)
}
render (){
// return 有且仅有一个根标签!
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 (){
/*
在子组件中不能直接改变父组件的状态。因此要使用父组件传递过来的函数。
相当于父组件(App)暴露了一个接口来修改状态,修改的逻辑在接口中已经订好了
(具体为在Todos前面插入一个新Todo)
那么如何触发这个接口的使用呢?向接口中传入怎样的参数呢?都是在子组件(Add)中进行的
具体:
1 读取输入的数据
2 检查合法性
3 合法则添加
*/
console.log('add - Add')
const todo = this.todoInput.value.trim(); //通过refs获取input标签
if(!todo){
return
}
console.log(todo)
this.props.addTodo(todo);
//清除input的输入
this.todoInput.value = '';
}
render (){
return (
<div>
<input type='text' 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{
constructor(props){
super(props);
}
render (){
const {todos} = this.props
return (
<ul>
{todos.map((todo, index)=><li key={index}>{todo}</li>)}
</ul>
)
}
}
//指定 list的参数的类型
List.propTypes = {
todos : PropTypes.array.isRequired
}
ReactDOM.render(<App />, document.getElementById('root'));