搭建环境

默认你已经安装好 node.js

安装 react 脚手架

学习的过程中,我们采用React官方出的脚手架工具 create-react-app

npm install -g create-react-app

如果提示没有权限,win 用户可以管理员打开终端,mac 用户 可以在前面加上 sudo

新建第一个项目

在指定文件下

create-react-app study-demo 

运行

cd study-demo
npm start

脚手架生成的项目目录介绍

  • README.md :这个文件主要作用就是对项目的说明。
  • package.json: 这个文件是webpack配置和项目包管理文件。
  • package-lock.json:这个文件用一句话来解释,就是锁定安装时的版本号,并且需要上传到git,以保证其他人再npm install 时大家的依赖能保证一致。
  • gitignore : 这个是git的选择性上传的配置文件。
  • node_modules :这个文件夹就是我们项目的依赖包。
  • public :公共文件,里边有公用模板和图标等一些东西。
  • src : 主要代码编写文件
    • index.js : 这个就是项目的入口文件
    • index.css :这个是index.js里的CSS文件
    • app.js : 这个文件相当于一个方法模块,也是一个简单的模块化编程
    • serviceWorker.js: 这个是用于写移动端开发的,PWA必须用到这个文件,有了这个文件,就相当于有了离线浏览的功能

组件的基础编写

修改App.js 文件

import React, {Component} from 'react'

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

这里的 class 是面向对象语言的用法

className 是React 为了区别于 class 的特殊处理

React中JSX语法基础

JSX 就是 Javascript和XML结合的一种格式。

React发明了JSX,可以方便的利用HTML语法来创建虚拟DOM

当遇到<,JSX就当作HTML解析

遇到{就当JavaScript解析

比如我们写一段JSX语法

<ul className="my-list">
    <li>Hello React</li>
    <li>I love React</li>
</ul>

相当于

var child1 = React.createElement('li', null, 'Hello React');
var child2 = React.createElement('li', null, 'I love React');
var root = React.createElement('ul', { className: 'my-list' }, child1, child2);

组件和普通JSX语法区别

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

JSX中使用三元运算符

<ul className="my-list">
    <li>Hellow {false?'React':'Word'}</li>
    <li>I love React</li>
</ul>

JSX中使用循环

jsx 可以自动展开数组

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

Fragment 标签

因为组件只能有一个根目录

空标签,不会在页面留下痕迹

相当于 vue的 template , 小程序的 block

响应式设计和数据绑定

React 不建议你直接操作 DOM 元素,而是要通过数据进行驱动,改变界面中的效果

数据定义在组件中的构造函数里constructor

constructor(props){
    super(props) //调用父类的构造函数,固定写法
    this.state={
        inputValue:'' , // input中的值
        list:[]    //列表
    }
}

绑定数据

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

绑定事件

render()方法的下面建立一个inputChange()方法

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

将事件绑定

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

​ 1. 必须要用 bind 设置一下指向(ES6的语法)

​ 2. 改变值需要使用 this.setState 方法

点击事件

<div>
    <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={addList}> 增加 </button>
</div>

addList(){
    this.setState({
        list:[...this.state.list,this.state.inputValue]
    })

}

注意点:

1. JSX 的点击事件写法是 onClick
1. React是禁止直接操作 state 的, 比如push,splice 都是不建议使用

JSX 代码注释

<Fragment>
    {/* 第一种写法写法 */}
    
    {
        // 第二种写法,此写法只能单独写一行
    }
</ Fragment>

JSX 解析HTML

可以使用 dangerouslySetInnerHTML 属性解决

<div dangerouslySetInnerHTML={{__html: this.state.htmlValue}}>

组件

父组件向子组件传值

父组件

import React,{Component,Fragment } from 'react'
import Item from './Item'

class Test extends Component{
	constructor(props){
    super(props)
    this.state={
        list:[1, 2] 
    }
	}

	render() {
		return (
			<Pragment>
				<ul>
    				{
      				this.state.list.map((item,index)=>{
        				return (
          				<Item key={index} content={item} />
        				)
      				})
    				}
  			</ul>  
			</ Pragment>
		)
	}
}

export default Test

子组件

import React, { Component } from 'react'; 
class Item extends Component { 

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

子组件向父组件传递数据

React有明确规定,子组件不能操作父组件里的数据,所以需要借助一个父组件的方法,来修改父组件的内容

import React,{Component,Fragment } from 'react'
import Item from './Item'

class Test extends Component{
	constructor(props){
    super(props)
    
    this.handleClick=this.handleClick.bind(this)
    
    this.state={
        list:[1, 2] 
    }
	}
	
	handleClick(key){
     const arr = this.state.list.filter(item => item !==key)
     this.setState({
        list: arr
    })
  }

	render() {
		return (
			<Pragment>
				<ul>
    				{
      				this.state.list.map((item,index)=>{
        				return (
          				<Item key={index} content={item} handleDel={handleClick} />
        				)
      				})
    				}
  			</ul>  
			</ Pragment>
		)
	}
}

export default Test

子组件

import React, { Component } from 'react'; 
class Item extends Component { 

		handleClick(key){
    	this.props.handleDel(key)
		}

    render() { 
        return ( 
            <div onClick={()=> handleClick(this.props.content).bind(this)}>{this.props.content}</div>
         );
    }
}
export default Item;

prop-types 校验传递的值

在vue中,我们 props: {xxx: { type: xxx, isRequire: true, default: xxx }} 可以校验传递的值

在 react 中 我们可以用 prop-types

import React, { Component } from 'react'; 
import PropTypes from 'prop-types'

class Item extends Component { 

		handleClick(key){
    	this.props.handleDel(key)
		}

    render() { 
        return ( 
            <div onClick={()=> handleClick(this.props.content).bind(this)}>{this.props.content}</div>
         );
    }
}

Item.PropTypes = {
	content: PropTypes.string,
	handleDel: PropTypes.func
}

export default Item;

isRequired关键字了,它表示必须进行传递,如果不传递就报错

Item.PropTypes = {
	content: PropTypes.string.isRequired,
	handleDel: PropTypes.func.isRequired
}

设置默认值

Item.defaultProps = {
  content: '默认的值'
}

Ref 的使用

跟vue一样,定义了ref,就能拿到该元素的大部分信息

定义

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

使用

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

React 生命周期

React生命周期分为四个大阶段

Initialization:初始化

Mounting:挂载

Updation:更新

Unmounting:销毁

注意点:

​ constructor 不是生命周期函数,虽然它和生命周期函数的性质一样

Initialization

​ 定义属性(props)和状态(state)

Mounting

  1. componentWillMount : 在组件即将被挂载到页面的时刻执行。
  2. render : 页面state或props发生变化时执行。
  3. componentDidMount : 组件挂载完成时被执行。

注意点:

componentWillMountcomponentDidMount 这两个生命周期函数,只在页面刷新时执行一次,而render函数是只要有state和props变化就会执行

Updation

  1. shouldComponentUpdate 函数会在组件更新之前,自动被执行。它要求返回一个布尔类型的结果,必须有返回值,常用于组件性能优化。
  2. componentWillUpdate 在组件更新之前,但 shouldComponenUpdate 之后被执行。
  3. componentDidUpdate 在组件更新之后执行,它是组件更新的最后一个环节
  4. componentWillReceiveProps 子组件接收到父组件传递过来的参数,父组件render函数重新被执行,这个生命周期就会被执行

注意点:

​ 如果shouldComponentUpdate 返回false,后面的函数就不会被执行了。

componentWillReceiveProps 组件接收到父组件传递过来的参数,父组件render函数重新被执行,这个生命周期就会被执行

Unmounting

componentWillUnmount 函数时组件从页面中删除的时候执行

利用shouldComponentUpdate 优化组件

在上面的代码中,我们输入框频繁输入,会导致子组件频繁刷新,导致性能损耗

shouldComponentUpdate 函数就可以简单的解决调这个问题

shouldComponentUpdate(nextProps,nextState){
    if(nextProps.content !== this.props.content){
        return true
    }else{
        return false
    }
}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐