08 组件组合使用

需求:组件化实现此功能

  1. 显示所有todo列表

  2. 输入文本, 点击按钮显示到列表的首位, 并清除输入的文本

第一步,定义组件并渲染静态组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/prop-types.js"></script>
    <script src="../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
</body>
</html>
<script type="text/babel">
   
     //App根组件
    class AppComponent extends React.Component{
        render(){
            return(
                <div>
                    <h1>Simplet TODO List</h1>
                    <AddComponent/>
                    <ListComponent/>
                </div>
            )
        }
    }

    //上方添加组件
    class AddComponent extends React.Component {
           render() {
               return (
                   <div>
                        <input type="text"/>
                        <button>Add#1</button>
                   </div>
               )
           }
    }

    //下方列表组件
    class ListComponent extends React.Component {
            render() {
                return (
                    <ul>
                        <li>1111</li>
                        <li>2222</li>
                        <li>3333</li>
                    </ul>
                )
            }
    }
    ReactDOM.render(<AppComponent/>,document.getElementById("test"));
</script>

<!-- 此页面
1,拆分为三个组件
2,使用组件实现静态页面效果 -->

第二步,动态显示初始化数据

注意考虑:数据保存在哪个组件中?

       看数据是某个组件需要它(给它),还是某些组件需要它(给包含它们的父组件)
这里,AddComponent要提供数据并且Add按钮后面的数字是数据的长度加1,ListComponent 要显示数据,都需要用到数据,所以数据应该保存在 AppComponent 中
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/prop-types.js"></script>
    <script src="../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
</body>
</html>
<script type="text/babel">

    //根组件
    class AppComponent extends React.Component{
        constructor(props){
            super(props);
            //初始化状态
            this.state={
                todos:['吃饭','睡觉','敲代码'],
            }
        }
        render(){
            const {todos} =this.state;//ES6解构赋值的写法,相当于this.state.todos,这里需要接收的是状态
            return(
                <div>
                    <h1>Simplet TODO List</h1>
                    <AddComponent dataNum={todos.length}/> 给添加组件传一个dataNum属性,属性值是数组长度
                    <ListComponent todos={todos}/> 给列表组件传入todos属性,属性值是组件对象中的数组
                </div>
            )
        }
    }
    //添加组件
    class AddComponent extends React.Component {
           render() {
               return (
                   <div>
                        <input type="text"/>
                        <button>Add#{this.props.dataNum+1}</button>
                   </div>
               )
           }
    }
    //添加组件接收dataNum属性并给予类型限制和必要性限制
    AddComponent.propTypes = {
        dataNum:PropTypes.number.isRequired,
    }

    //列表组件
    class ListComponent extends React.Component {
            render() {
                const { todos } = this.props; //ES6解构赋值的写法,这里接收到的是属性
                return (
                    <ul>
                        {todos.map((todo,index)=><li key={index}>{todo}</li>)}
                    </ul>
                )
            }
            
    }
    //列表组件接收todos属性,并给予类型限制和必要性限制
    ListComponent.propTypes={
        todos:PropTypes.array.isRequired,
    }
    
    ReactDOM.render(<AppComponent/>,document.getElementById("test"));
</script>

 第三步,做交互,输入一个 todo ,点击Add按钮,这个 todo 要添加到 state 中的 todos 数据中,并更新 todos 状态

考虑:

我们是点击按钮时要改变父组件中的状态,是在子组件中改变父组件的状态,但这是不允许的,因为状态在哪个组件,更新状态的行为就应该在哪个组件,这里的行为就是指 添加todo 这个事件。

方案:

父组件定义函数,通过标签传递给子组件,子组件调用
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6     <title>Document</title>
 7     <script src="../js/react.development.js"></script>
 8     <script src="../js/react-dom.development.js"></script>
 9     <script src="../js/prop-types.js"></script>
10     <script src="../js/babel.min.js"></script>
11 </head>
12 <body>
13     <div id="test"></div>
14 </body>
15 </html>
16 <script type="text/babel">
17    
18     //根组件
19     class AppComponent extends React.Component{
20         constructor(props){
21             super(props);
22             //初始化状态
23             this.state={
24                 todos:['吃饭','睡觉','敲代码'],
25             }
26             this.addData=this.addData.bind(this); //addData()方法是自己定义的,帮它的this绑定到组件对象上
27         }
28         addData(todo){
29             const {todos}=this.state;
30             todos.unshift(todo);//unshift()向数组的头部添加元素,push()向数组的尾部添加元素
31             //更新状态
32             this.setState({todos});
33         }
34         render(){
35             const {todos}=this.state;
36             return(
37                 <div>
38                     <h1>Simplet TODO List</h1>
39                     <AddComponent dataNum={todos.length} addData={this.addData} todos={todos}/> 
40                     <ListComponent todos={this.state.todos}/>
41                 </div>
42             )
43         }
44     }
45     //添加组件
46     class AddComponent extends React.Component {
47            constructor(props){
48                super(props);
49                this.addLi=this.addLi.bind(this); //addLi()自己定义的方法,注意绑定this
50            }
51            addLi(){
52              alert(this.input.value);//获取的输入框中的值
53              const text=this.input.value.trim() //读取输入数据
54              if(!text){ //考虑输入不合法的情况,比如输入的是一个空字符串,就不添加
55                  return;
56              }
57              this.props.addData(text);//调用接收到的addData()这个方法,并传入参数(输入框中的值)
58              this.input.value=''; //清除输入框
59            }
60            render() {
61                return (
62                    <div>
63                         <input type="text" ref={input=>this.input=input}/>
64                         <button onClick={this.addLi}>Add#{this.props.dataNum+1}</button>
65                    </div>
66                )
67            }
68     }
69     AddComponent.propTypes={
70         dataNum:PropTypes.number.isRequired,
71         addData:PropTypes.func.isRequired,//函数也是一个属性,可以以同样的方式接收
72         todos:PropTypes.array.isRequired,
73     }
74 
75     //列表组件
76     class ListComponent extends React.Component {
77             render() {
78                 const { todos } = this.props;
79                 return (
80                     <ul>
81                         {todos.map((todo,index)=><li key={index}>{todo}</li>)}
82                     </ul>
83                 )
84             }
85             
86     }
87     ListComponent.propTypes={
88         todos:PropTypes.array.isRequired,
89     }
90     
91     ReactDOM.render(<AppComponent/>,document.getElementById("test"));
92 </script>
补充,考虑用户输入的 todo 列表中已经存在就不添加,只有当用户输入的内容在 todos 中没有出现过才添加
在 addLi() 中添加一个判断
 
 
原文地址:https://www.cnblogs.com/shanlu0000/p/12487009.html