# React入门

# 运用React实现TodoList功能

# 创建React应用

参考官网地址:Create React App

首先安装 Node >= 8.10 和 npm >= 5.6

npx create-react-app my-app  //创建名称为my-app的应用
cd my-app
npm start
1
2
3

# 实战代码——编写TodoList列表项组件

# index.js是入口

//index.js是入口
//引入React帮助理解React的语法,eg:以大写字母开头的都是组件、标签语法等等
import React from 'react';
//把组件渲染到DOM节点上
import ReactDOM from 'react-dom';

//App是最外层的组件,在React中以大写字母开头的都是组件
//import App from './App';

//引入TodoList组件(在同级目录下创建TodoList.js)
import TodoList from './TodoList';

//引入css
import './style.css';

//把App组件渲染到id为root的标签中
//ReactDOM.render(<App />, document.getElementById('root'));

//TodoList列表
ReactDOM.render(<TodoList />, document.getElementById('root'));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 编写父组件TodoList

import React , { Component , Fragment } from 'react';
//引入子组件TodoItem(在同级目录下创建TodoItem.js)
import TodoItem from './TodoItem';

/*定义一个叫做TodoList的React组件,
只要组件继承Component就变成了组件。
那么组件是什么呢?组件就是页面中的一部分。
*/
class TodoList extends Component{

  /*ES6语法:当TodoList刚被创建的时候,constructor会自动执行*/
  constructor(props){
    super(props);
    //创建了数据项并存储
    this.state = {
        //初始化list
        list:[
        'learn react1',
        'learn react2'
        ],
        //定义inputValue
        inputValue: ''
    }

    //bind(this)让函数的this指向TodoList组件
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleButtonClick = this.handleButtonClick.bind(this);
    this.handleDelete = this.handleDelete.bind(this);
  }

  //按钮点击事件
  handleButtonClick(){
    //调用setState改变数组
    this.setState({
        list: [...this.state.list,this.state.inputValue],//...是ES6语法,把之前的内容放在里面,同时也增加了内容
        inputValue: ''//点击后清空inputValue,输入框DOM节点又引用了这个值
    })
  }

  //输入框输入事件
  handleInputChange(e){
    this.setState({
        inputValue: e.target.value//修改inputValue变为输入框输入的值(input DOM节点的值)
    })
  }

  //列表项的删除,React的思想不让操作DOM,只需要操作数据即可
  // handleItemClick(index){
  //   const list = [...this.state.list];//尽量不要直接操作原list,作一个副本进行操作,让性能和可调试性达到最优。
  //   list.splice(index,1);
  //   this.setState({
  //       list //ES6中键和值是一样的话,可以直接这么写
  //       //list: list //将新的list覆盖掉之前的list
  //   })
  // }

  //父组件与子组件通信
  //父组件通过属性的形式向子组件传递参数
  //然后子组件通过属性的形式(props)接收从父组件传递过来的参数
  //列表项的删除
  handleDelete(index){
    const list = [...this.state.list];
    list.splice(index,1);
    this.setState({
        list 
    })
  }

  //获取列表项
  getTodoItems(){
    return (
        /*map是对数组做循环的函数*/
        this.state.list.map((item,index) => {
            // return <li key={index} 
            //         onClick={this.handleItemClick.bind(this,index) /*bind(this)让函数的this指向TodoList组件*/}>
            //         {item}
            //        </li> /*循环展示时react要求每一项内容都要有key值且值唯一*/

            return (
                <TodoItem 
                deleteTodoItem={this.handleDelete}
                key={index} 
                index={index} 
                content={item 
                /*将item值传递给TodoItem组件,
                即:父组件通过属性的形式向子组件传递参数*/
                } />
            )
        })
    )
  }

  //render()函数负责页面要显示的内容
  render(){
    //return的内容就是页面内容
    //这里使用的是jsx语法,可以直接使用标签显示的语法结构
    return (
        <Fragment>
            <div>
              <input 
              value={this.state.inputValue} 
              onChange={this.handleInputChange
              /*输入后改变了inputValue,从而改变了该节点的值*/ 
              }/>
              <button /*style={{background: 'red',color: '#fff'}} 最外层{}代表里面是js表达式,里面的{}代表js对象*/ 
              className='red_btn'             
              onClick={this.handleButtonClick}>add</button>
            </div>
            <span>React强调的是面向数据编程,对于DOM的操作React会自动帮你处理</span>
            <ul>{this.getTodoItems()}</ul>
        </Fragment>
    );
  } 
}

/*定义完组件后导出,然后其他文件中才可以导入,导出和导入是配对使用的*/
export default TodoList;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

# 编写子组件TodoItem

import React , {Component} from 'react';

//列表项的子组件
class TodoItem extends Component{

    constructor(props){
        super(props);
        this.handleDelete = this.handleDelete.bind(this);
    }

    //子组件如果想和父组件进行通信,子组件要调用父组件传递过来的方法
    //通过deleteTodoItem属性传递过来handleDelete方法,
    //然后子组件调用了父组件的handleDelete并传递了索引值index
    handleDelete(){
        const { deleteTodoItem,index } = this.props;//ES6解构
        deleteTodoItem(index);
        // this.props.deleteTodoItem(this.props.index);
    }

    render(){
        const { content } = this.props;//this.props.content 通过属性的形式(props)接收从父组件传递过来的参数
        return (
            <div 
            onClick={this.handleDelete} >
            {content}
            </div>
        )
    }
}

export default TodoItem;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 编写style.css,使用css样式粗犷修饰

.red_btn{
    background: red;
    color: #fff;
}
1
2
3
4

至此,TodoList列表项组件的编写已完成。