React响应式设计和数据绑定

856 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第9天 jQuery和React的区别 jQuery以事件驱动,原理是通过事件的触发来操作DOM改变页面。 React 以数据驱动,为单向数据流,通过监测数据变化来完成页面的改变。

  1. 响应式设计和数据的绑定 React不建议直接操作DOM元素,而是通过数据进行驱动,改变页面的效果。React会根据数据的变化,自动的帮助你完成页面的改变。所以在写React时,无需关注DOM等相关操作,只需要关注数据的操作就可以了。

在上一节,已经编写好了Child.js组件的基础框架,这一节,首先需要定义数据。数据定义在Child.js组件中的构造函数constructor。 // js的构造函数,用于其他函数执行
constructor(props) {
// 调用父类的构造函数,固定写法
super(props)
// 定义数据
this.state = {
// input中的默认值
inputValue: '',
// li列表项
list: []
}
}

`React`中的数据绑定和`Vue`几乎一样,也是采用**字面量**的形式,也就是使用`{}`来标注,  
其实也算是`JavaScript`代码的一种声明,现在我们要把`inputValue`值绑定到`input`框中,
只需要向下面这样就好。说白了就是在`JSX`中使用`JavaScript`代码。
	<input value = {this.state.inputValue} />

在可以返回浏览器看到绑定效果。可以在this.state对面里的inputValue属性修改一下默认值看看效果。

值得注意的是:在这里没有进行任何的DOM操作,但是界面已经发生了变化,这就是React的神奇之处,它是自动帮我们做的。因为它会自动感知数据的变化。

  1. 绑定事件 这时候在界面中的文本框输入值,是没有任何变化的。因为强制绑定了inputValue的值,如果想要改变,需要绑定 响应事件 ,改变inputValue的值,比如绑定一个改变事件,这个事件执行inputChange()(此时还没写)方法。如下:
    目前还没有inputChange()这个方法,所以需要在render()方法的下面建立一个inputChange()方法,如下:
    // e为事件对象。里面有很多方法和属性。
    inputChange(e) {
    console.log(e)
    }
    这时候响应事件已经可以使用了。但是想获取自己输入的值,需要从事件对象中拿到对应的属性。
    inputChange(e) {
    // target为当前事件对象本身。此处为input文本框
    console.log(e.target.value)
    }
    此时可以控制台可以看到获得输入的值,如果直接改变inputValue的值会报错。
    inputChange(e) {
    // target为当前事件对象本身。此处为input文本框
    console.log(e.target.value)
    this.state.inputValue = e.target.value
    }
    返回浏览器,会发现报错,其实这里范了两个错误:

  2. this指向不对,需要重新用 bind 设置一下指向。

  3. React中改变值需要使用 this.setState 方法。

第一种错误可以在JSX部分中,利用 bind 进行绑定就好。
<input value = { this.state.inputValue } onChange = { this.inputChange.bind(this) } />

第二种错误需要使用 setState 方法改变值。

inputChange(e) {
	this.setState({
		inputValue: e.target.value
	})
}

至此,返回浏览器查看效果,成功。

PS: React中绑定this的4种方式如下:

1. render方法中使用bind
class App extends React.Component {
	handleClick() {
		console.log('this >', this)
	}
	render() {
		return (
			<div onClick = { this.handleClick.bind(this) } test </div>
		)
	}
}

这种方式很简单,也是大多数初学者开发在遇到问题后采用的一种方式,但是由于组件每次执行render将会重新分配函数,这会影响性能。特别是在做了一些性能优化之后,它会破坏PureComponent性能。不推荐使用。

2. render方法中使用箭头函数
class App extends React.Component {
	handleClick() {
		console.log('this >', this)
	}
	render() {
		return (
			<div onClick = { e => this.handleClick(e) } test </div>
		)
	}
}

使用了es6的上下文绑定来让this指向当前组件,但是它和上面的一样有性能问题。不推荐使用。

3. 构造函数中bind
class App extends Component {
	constructor(props) {
		super(props)
		this.handleClick = this.handleClick.bind(this)
	}
	handleClick() {
		console.log('this >', this)
	}
	render() {
		<div onClick = { this.handleClick }> test </div>
	}
}

为了避免在render中绑定this引发可能的性能问题,可以在constructor中预先进行绑定。然而这种方法很明显在可读性和维护性上没有上面的第一种和第二种有优势,但是第一种和第二种又有潜在的性能问题不推荐,所以采用第四种方式是最合适的。

4. 定义阶段使用箭头函数
class App extends Component {
	constructor(props) {
		super(props)
	}
	handleClick = () => {
		console.log('this >', this)
	}
	render() {
		return (
			<div onClick = { this.handleClick }> test </div>
		)
	}
}

这种方法有很多优化:

  • 箭头函数会自动绑定到当前组件的作用域中,不会被call改变;
  • 避免了第一种和第二种的可能存在的性能问题
  • 避免了第三种绑定时大量重复的代码。