欢欢的React学习笔记

  • A+
所属分类:安全开发

前言

学习React是今年的计划之一,再加上之前学习了Vuejs,想了解两者之间的区别,因此大致学习下React,有机会再用React写一个项目。

React的三大体系

用于Web开发和组件的编写ReactNative用于移动端开发ReactVR用于虚拟现实技术的开发

安装

安装Nodejs

使用Reactjs最原始的方法就是script标签引入,但这太low了,并且在工作当中也不会这样引用,因此安装Nodejs来使用react最佳~打开下面的网址,自行安装即可。 Nodejs中文网址:http://nodejs.cn/

脚手架安装

安装完Nodejs后,使用npm命令安装脚手架

npm install -g create-react-app

创建第一个React项目

create-react-app demo

目录结构

src:项目代码主目录public:公共文件,例如可以存储样式文件、图标等等node_modules:项目的依赖包gitignore:git的选择性上传配置文件package-lock.json:锁定安装时的版本号,以保证其他人再npm install时大家的依赖能保证一致

src文件夹

index.js:项目的入口文件index.css:index.js里的css文件app.js:相当于一个方法模块,也是一个简单的模块化编程serviceWorker.js:用于移动端开发,PWA必须用到这个文件,有了这个文件,就相当于有了离线浏览的功能

编写第一个HelloWord

index.js 入口文件的编写

src目录下,新建一个文件index.js,写入下面4行代码

import React from 'react'
import ReactDOM form 'react-dom'
import App from './App' // 这里其实省略了.js,完整是./App.js,但这里可以省略,react会自动识别
ReactDOM.render(<App />,document.getElementById('root'))

上面的代码,首先引入了React必要的两个文件,然后引入了一个APP组件,再使用ReactDOM渲染到了rootID上.PS:这个root ID是在publicindex.html中。

app组件的编写

import React, {Component} from 'react'  // ES6的语法-解构赋值,当然也可以写成下面两行
// import React from 'react'
// const Component = React.Component

class App extends Component{
render(){
return (
<div>
Hello React
</div>
)
}
}
export default App;

React中JSX语法

简介

javascript + xml = jsx。当遇到<,JSX就当作HTML解析,遇到{就当JS解析,举个例子(JSX语法)

<ul className="list">
<li>视觉志</li>
<li>I love React</li>
</ul>

而在以前写一段JS:

var child1 = React.createElement('li', null, '视觉志');
var child2 = React.createElement('li', null, 'I love React');
var root = React.createElement('ul', { className: 'list' }, child1, child2);

从代码量上看出JSX语法大量简化了我们的工作.

小坑

自定义的组件必须首写字母要进行大写,而JSX是小写字母开头的

使用三元运算符


import React from 'react'
const Component = React.Component

class App extends Component{
render(){
return (
<ul className="my-list">
<li>{false?'视觉志':'iobiji.com'}</li>
<li>I love React</li>
</ul>
)
}
}

export default App;

实例

新建一个组件

import React,{Component} from 'react'

class Demo extends Component{
render(){
return (
<div>
<ul>
<li>aaa</li>
<li>bbb</li>
</ul>
</div>
)
}
}
export default Demo;

组件外层包裹原则

划重点,比如上面的代码,去掉最外层的<div>就会报错,因为React要求必须在一个组件的最外层进行包裹,这就类似于Vuejs中的只允许一个根div

Fragment标签

加上最外层的DIV,组件就是完全正常的,但布局就偏不需要这个最外层的标签怎么办?比如在作Flex布局时,外层还真的不能有包裹元素。这种矛盾其实React已经给了我们解决方案,也就是<Fragment>标签 引入:

import React,{Component,Fragment} from 'react'

然后把最外层的<div>换成标签即可.

响应式设计和数据的绑定

React不建议直接操作DOM元素,而是要通过数据进行驱动,改变界面中的效果。React会根据数据的变化,自动的帮助你完成界面的改变。所以在写React代码时,你无需关注DOM相关的操作,只需要关注数据的操作就可以了(这也是React如此受欢迎的主要原因,大大加快了我们的开发速度)。 数据定义在组件中的构造函数里constructor

constructor(props){
super(props) //调用父类的构造函数,固定写法
// 还有就是一般this在这里绑定,特别是在高级组件开发中,会有很大的作用
this.state={
inputValue:'' , // input中的值
list:[]
}
}

React中的数据绑定和Vue中几乎一样,就是使用{}来标注,其实这也算是js代码的一种声明。比如现在我们要把inputValue值绑定到input框中,只要写入下面的代码就可以了。其实说白了就是在JSX中使用js代码。

<input value={this.state.inputValue} /> 

绑定事件

这时候到界面的文本框中去输入值,是没有任何变化的,这是因为我们强制绑定了inputValue的值。如果要想改变,需要绑定响应事件,改变inputValue的值。比如绑定一个改变事件,这个事件执行inputChange()(当然这个方法还没有)方法。 在render()方法下建立一个inputChange()方法:

inputChange(e){
console.log(e.target.value);
this.state.inputValue = e.target.value;
}

其实,这里犯了两个错误:

1.this的指向不对,需要重新用bind设置指向(ES6的语法)2.React中改变数据需要使用this.setState方法 解决:

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

另外需要在inputChange方法加入setState方法来改变值:

inputChange(e){
// console.log(e.target.value);
// this.state.inputValue=e.target.value;
this.setState({
inputValue:e.target.value
})
}


key值错误解决

<ul>
{
this.state.list.map((item,index)=>{
return <li key={index+item}>{item}</li>
})
}
</ul>

数组下标的传递

<ul>
{
this.state.list.map((item,index)=>{
return (
<li
key={index+item}
onClick={this.deleteItem.bind(this,index)}
>
{item}
</li>
)
})
}
</ul>

遍历

<ul>
{
this.state.list.map((item,index)=>{
return (
<ServiceItem
key={index+item}
list={item}
index={index} />
)
})
}
</ul>

JSX防踩坑的几个地方

JSX代码注释

    //第一次写注释,这个是错误的
<div>
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

正确的写法有以下两种:

# 第一种
{/* 正确注释的写法 */}
# 第二种
{
//正确注释的写法
}

第二种不太优雅,推荐第一种注释方法,当然使用编辑器的快捷注释也可以,最简单的方法

JSX中的class陷阱

使用class属性是错的,必须使用className,它是防止JS中的class类名冲突。

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

JSX中的html解析问题

如果想在文本框里输入一个<h1>标签,并进行渲染。默认是不会生效的,只会把<h1>标签打印到页面上,这并不是我想要的。如果工作中有这种需求,可以使用dangerouslySetInnerHTML属性解决。具体代码如下:

<ul>
{
this.state.list.map((item,index)=>{
return (
<li
key={index+item}
onClick={this.deleteItem.bind(this,index)}
dangerouslySetInnerHTML={{__html:item}}
>
</li>
)
})
}
</ul>

JSX中<label>标签的坑

先看下面的代码,我们在文本框前面加入一个<label>

<div>
<label for="service">加入服务:</label>
<input id="service" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

console会有红色警告提示的。大概意思是不能使用for.它容易和javascript里的for循环混淆,会提示你使用htmlFor

<div>
<label htmlFor="service">加入服务:</label>
<input id="service" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

组件的拆分

新建一个组件

import React, { Component } from 'react';
class ServiceItem extends Component { //cc

render() {
return (
<div>服务列表</div>
);
}
}
export default ServiceItem;

第二种方法

import React from 'react';
const ServiceItem = (props) => {
<div>服务列表</div>
}
export default ServiceItem;

在另外一个组件中使用import引入这个组件:

import ServiceItem from './ServiceItem'

然后直接写入<ServiceItem />标签即可

父子组件的传值

使用组件属性的形式,父组件传值给子组件。比如加入list属性,然后给属性传值{item},这样就完成了父组件向子组件传值.

<ServiceItem list={item} />

在接收数据的组件通过使用this.props.xxx的形式接收即可,例如

import React, { Component } from 'react';
class ServiceItem extends Component { //cc

render() {
return (
<div>{this.props.list}</div>
);
}
}
export default ServiceItem;

子组件向父组件传递数据

首先子组件绑定点击事件:

import React, { Component } from 'react';

class ServiceItem extends Component {
render() {
return (
<div onClick={this.handleClick}>{this.props.list}</div>
);
}

handleClick(){
console.log('点击了')
}

}

export default ServiceItem;

父组件向子组件传递点击删除方法

<ul>
{
this.state.list.map((item,index)=>{
return (
<ServiceItem
key={index+item}
list={item}
index={index}
//关键代码-------------------start
deleteItem={this.deleteItem.bind(this)}
//关键代码-------------------end
/>
)
})
}
</ul>

子组件调用父组件传递的方法

import React, { Component } from 'react';
class ServiceItem extends Component {
constructor(props){
super(props)
this.handleClick=this.handleClick.bind(this)
}

render() {
return (
<div onClick={this.handleClick}>
{this.props.list}
</div>
);
}
handleClick(){
this.props.deleteItem(this.props.index)
}
}

export default ServiceItem;

ref的使用方法

代替原来的e.target.value

以前的案例中使用了e.target,这并不直观,也不好看。这种情况可以使用ref来进行解决。

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

如果要使用ref来进行,需要现在JSX中进行绑定, 绑定时最好使用ES6语法中的箭头函数,这样可以简洁明了的绑定DOM元素。

<input 
id="addService"
className="input"
value={this.state.inputValue}
onChange={this.inputChange.bind(this)}
//关键代码——----------start
ref={(input)=>{this.input=input}}
//关键代码------------end
/>

绑定后可以把上边的类改写成如下代码:

inputChange(){
this.setState({
inputValue:this.input.value
})
}

React和Vue的对比

React.js相对于Vue.js,它的灵活性和协作性更好一点,个人认为react是UI框架,而vue是数据驱动框架,因为vue.js有着丰富的API,实现起来更加简单快速。


本文始发于微信公众号(千寻瀑):欢欢的React学习笔记

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: