zoukankan      html  css  js  c++  java
  • React笔记03——React实现TodoList

    1 什么是JSX语法?

    原生JS中,要向页面中挂载html标签,标签一定是被引号''包起来的:document.getElementById('root').append('<div>hello world</div>');

    但在JSX语法中,不需要用引号包起来,这是JSX语法中的显著特点。

    JSX中有两种类型的标签:

    1⃣️普通的html标签(如App.js中的<div>hello</div>)

       一般标签的首字母是小写的

    2⃣️组件标签(如index.js中的<App />)

       标签的首字母必须是大写的   

    2 React中的数据驱动思想和事件绑定

    数据驱动思想:

    React的所有功能都不直接操作DOM,而是直接操作数据。

    在我们的TodoList项目中一共有两种数据:input中输入的数据页面上显示的数据,找到了它们就可以把网页完整渲染出来了。

    事件绑定:

    原生JS中为input绑定事件,使用的是onchange属性;

    在React中要写成onChange,接着为其绑定一个函数,并在render函数上方定义这个函数。

    <input value = {this.state.inputValue} onChange = {this.handleInputChange.bind(this)}/>

    3 使用React编写TodoList

    1)创建入口文件index.js,创建组件文件TodoList.js,在index.js中引入TodoList组件。

    //index.js
    import React from 'react';
    import ReactDOM from 'react-dom';
    import TodoList from './TodoList';
    
    ReactDOM.render(<TodoList />, document.getElementById('root'));

    2) 完善TodoList组件

    1⃣️简单布局

    render()函数只能识别一个标签,如果页面中有多个平级标签,要把它们最终包到一个div中,使得最外层只有一个标签。

    但是在一些复杂的逻辑中,要求多个平级标签必须直接暴露在id为root的div中,不允许在外层再包裹一个div,那该怎么办呢?

    React 16中提供了一个新的占位符组件Fragment,我们可以在TodoList组件中引入它,把多个标签统一放到Fragment标签中,就可以解决报错问题,且不会在页面中添加多余的标签。

    //TodoList.js
    import React , { Component , Fragment } from 'react';
    
    class TodoList extends Component {
    	render() {
    		return (
        		<Fragment>
        			<input />
        			<ul>
        				<li>learn React</li>
        				<li>learn React</li>
        			</ul>
        		</Fragment>
      		);
    	}
    }
    
    export default TodoList; 

    2⃣️在组件中定义项目中的数据

    在我们的TodoList项目中一共有两种数据:input中输入的数据页面上显示的数据,找到了它们就可以把网页完整渲染出来了。

    在render函数上方定义一个新的函数——constructor()函数

    在组件被使用的一瞬间,会首先自动执行constructor函数,组件会接收外部传入的参数,并使用super函数把参数传递给其基类(基类就是父类,派生类就是子类)的构造函数中,在super后我们可以通过this.state来定义数据!【这里涉及到React的底层原理】

    定义完数据后,我们需要在页面标签中引用这个数据,但是不能直接使用<input value = this.state.inputValue/>这种写法,因为这里使用的是JSX语法,如果直接将属性值 = 一个JS中的变量或者表达式,会报错,因此要将变量或表达式用花括号{}括起来——<input value = {this.state.inputValue}/>

    但是这里的数据是静态的,我们在输入框输入新的内容或想对其进行修改时会发现并不奏效,为了使数据能够动态的变化,我们需要为input绑定一个事件。

    import React , { Component , Fragment } from 'react';
    
    class TodoList extends Component {
    	constructor(props) {
    		super(props);
    		this.state = {
    			inputValue:'hello world',
    			list:[]
    		}
    	}
    	render() {
    		return (
        		<Fragment>
        			<input value = {this.state.inputValue}/>
        			<ul>
        				<li>learn React</li>
        				<li>learn React</li>
        			</ul>
        		</Fragment>
      		);
    	}
    }
    
    export default TodoList; 

    3⃣️事件绑定

    原来的this是undefined,input中数据变化,调用this.state时会报错,这里用es6中的bind方法,使this变为当前组件。然鹅,input中的值还是没有同步变化。。。

    这是因为我们不能直接通过this.state来修改数据,而是要通过一个函数——this.setState()函数

    import React , { Component , Fragment } from 'react';
    
    class TodoList extends Component {
    	constructor(props) {
    		super(props);
    		this.state = {
    			inputValue:'hello world',
    			list:[]
    		}
    	}
    	handleInputChange(e) {
    		this.setState({
    			inputValue: e.target.value
    		});
    	}
    	render() {
    		return (
        		<Fragment>
        			<input value = {this.state.inputValue} 
        				   onChange = {this.handleInputChange.bind(this)}/>
        			<ul>
        				<li>learn React</li>
        				<li>learn React</li>
        			</ul>
        		</Fragment>
      		);
    	}
    }
    
    export default TodoList; 

    4⃣️处理list中的数据

    根据list中的数据的情况,将数据循环显示到页面中;使用es6中的map函数实现数组循环。

    list中数据的显示:

    import React , { Component , Fragment } from 'react';
    
    class TodoList extends Component {
    	constructor(props) {
    		super(props);
    		this.state = {
    			inputValue:' ',
    			list:['learn React','learn Vue','learn JS']
    		}
    	}
    	handleInputChange(e) {
    		this.setState({
    			inputValue: e.target.value
    		});
    	}
    	render() {
    		return (
        		<Fragment>
        			<input value = {this.state.inputValue} 
        			       onChange = {this.handleInputChange.bind(this)}/>
        			<ul>
        				{
        					this.state.list.map((value,index) => {
        					return <li>{value}</li>
        					})
        				}
        			</ul>
        		</Fragment>
      		);
    	}
    }
    
    export default TodoList;  

    此时,数据能够成功显示,但控制台会报出警告⚠️index.js:1 Warning: Each child in a list should have a unique "key" prop.

    为了使list中每个值能够唯一对应,我们需要为每条数据定义key属性

    <li key = {index}>{value}</li>

    动态显示list中数据:

    实现在input输入数据后,敲回车,数据同步添加到list中。

    我们要再为input绑定一个事件——onKeyUp

            handleKeyUp(e) {
    		if(e.keyCode === 13){
    			// const list = [...this.state.list]; 
    		//es6中语法,相当于const list = ['learn React','learn Vue','learn JS']
    		const list = [...this.state.list,this.state.inputValue]; 
    		this.setState({
    			list:list
    		});
    		}	
    	}
    	render() {
    		return (
        		<Fragment>
        			<input value = {this.state.inputValue} 
        				   onChange = {this.handleInputChange.bind(this)}
        				   onKeyUp = {this.handleKeyUp.bind(this)}/>
        			<ul>
        				{
        					this.state.list.map((value,index) => {
        					return <li key = {index}>{value}</li>
        					})
        				}
        			</ul>
        		</Fragment>
      		);
    	}
    }      

    进一步完善代码,对代码进行精简⬇️:

    将初始list值置为空数组;

    key和对应值相同不用重复写{list:list},直接写{list}即可。

    实现按回车后,清空input中内容的功能。

    	handleKeyUp(e) {
    		if(e.keyCode === 13){
    			// const list = [...this.state.list]; 
    		//es6中语法,相当于const list = ['learn React','learn Vue','learn JS']
    		const list = [...this.state.list,this.state.inputValue]; 
    		this.setState({
    			list,
    			inputValue:''
    			});
    		}	
    	}

    删除list中的数据:

    实现点击某个列表项,就将其删除的功能。

    需要为li标签绑定点击事件。

    import React , { Component , Fragment } from 'react';
    
    class TodoList extends Component {
    	constructor(props) {
    		super(props);
    		this.state = {
    			inputValue:' ',
    			list:[]
    		}
    	}
    	handleInputChange(e) {
    		this.setState({
    			inputValue: e.target.value
    		});
    	}
    	handleKeyUp(e) {
    		if(e.keyCode === 13){
    			// const list = [...this.state.list]; 
    		//es6中语法,相当于const list = ['learn React','learn Vue','learn JS']
    		const list = [...this.state.list,this.state.inputValue]; 
    		this.setState({
    			list,
    			inputValue:''
    			});
    		}	
    	}
    	handleItemClick(index) {
    		const list = [...this.state.list]; 
    		list.splice(index,1);
    		this.setState({list});
    	}
    	render() {
    		return (
        		<Fragment>
        			<input value = {this.state.inputValue} 
        				   onChange = {this.handleInputChange.bind(this)}
        				   onKeyUp = {this.handleKeyUp.bind(this)}/>
        			<ul>
        				{
        					this.state.list.map((value,index) => {
        					return <li key = {index}
        							   onClick = {this.handleItemClick.bind(this,index)}
        							>
        							{value}
        							</li>
        					})
        				}
        			</ul>
        		</Fragment>
      		);
    	}
    }
    
    export default TodoList; 
    

    4 更多JSX语法细节

    1⃣️为标签绑定事件时,每次都要使用bind函数生成一个新函数来更新this,这样会对性能有影响。

    我们可以把对this的绑定放到constructor函数中来做,这样只在组件创建一瞬间执行这段代码,不会每次触发都要执行一遍,提高了性能。

    但如果bind函数中除了传递this还要传递其他参数,就不能使用这种方法了,因为这里每触发一次事件,传递但参数可能都是不同的,不能统一写到constructor中。

    2⃣️循环获取list中的内容这部分也可以单独放到一个函数中。

    3⃣️引入css样式

    在src目录下创建css文件:style.css

    在index.js中使用import引入css文件

    import './style.css';

    注:React会混淆定义组件的class关键字和标签中的class属性,因此要用className来定义标签中的class,否则控制台会有警告⚠️。

    4⃣️for

    实现点击输入框对应的label,输入框自动对焦。

    <label for = 'myinput'>请输入内容:</label>
    <input id = 'myinput'>

    可以实现效果,但是这时控制台会报警告⚠️index.js:1 Warning: Invalid DOM property `for`. Did you mean `htmlFor`?

    这是因为在JSX语法中,label中的for属性会与JS中的for循环关键字混淆,因此要把label中的for属性写为htmlFor

    5⃣️JSX语法中的注释

    JSX语法的标签中,无论是JS中的变量、表达式还是注释,都要用花括号{}包起来。

    6⃣️实现当输入内容为空时,不添加到页面

    增加一个判断条件

    e.target.value !== ''

    7⃣️html转义问题

    在输入框中输入html标签,显示到页面中时会被转义为普通文本,如果想显示标签的效果要使用dangerouslySetInnerHTML = {{__html:value}}

    dangerouslySetInnerHTML里面传的是一个JS对象

    最终代码:

    import React , { Component , Fragment } from 'react';
    import './style.css'
    
    class TodoList extends Component {
    	constructor(props) {
    		super(props);
    		this.handleInputChange = this.handleInputChange.bind(this);
    		this.handleKeyUp = this.handleKeyUp.bind(this);
    		this.state = {
    			inputValue:'',
    			list:[]
    		}
    	}
    	handleInputChange(e) {
    		this.setState({
    			inputValue: e.target.value
    		});
    	}
    	handleKeyUp(e) {
    		if(e.keyCode === 13 && e.target.value !== ''){
    			// const list = [...this.state.list]; 
    		//es6中语法,相当于const list = ['learn React','learn Vue','learn JS']
    		const list = [...this.state.list,this.state.inputValue]; 
    		this.setState({
    			list,
    			inputValue:''
    			});
    		}	
    	}
    	handleItemClick(index) {
    		const list = [...this.state.list]; 
    		list.splice(index,1);
    		this.setState({list});
    	}
    	getListItems() {
    		return this.state.list.map((value,index) => {
        		return <li key = {index}
        			       onClick = {this.handleItemClick.bind(this,index)}
        			       dangerouslySetInnerHTML = {{__html:value}}
        				>
        				</li>
        		})
    		}
    	render() {
    		return (
        		<Fragment>
        			<label htmlFor = 'myinput'>请输入内容:</label>
        			<input id = 'myinput'
        				   className = 'input'
        				   value = {this.state.inputValue} 
        				   onChange = {this.handleInputChange}
        				   onKeyUp = {this.handleKeyUp}/>
        			<ul>
        				{ this.getListItems() }
        			</ul>
        		</Fragment>
      		);
    	}
    }
    
    export default TodoList; 
    

      

  • 相关阅读:
    scrapy-redis使用以及剖析
    框架----Django之ModelForm组件
    框架----Django内置Admin
    django2.0集成xadmin0.6报错集锦
    为什么有些编程语言的数组要从零开始算
    Ubuntu安装Python3 和卸载
    安装MariaDB和简单配置
    ubuntu配置Python-Django Nginx+uwsgi 安装配置
    windows通过ssh连接虚拟机中的ubuntu步骤
    mysql数据库的相关练习题及答案
  • 原文地址:https://www.cnblogs.com/superjishere/p/12095783.html
Copyright © 2011-2022 走看看