react学习之路

一、简介

image.png

1、安装Node.js

使用React.js是可以用最原始的<Script>标签进行引入的,但是这实在是太low了,工作中也不会有这种形式进行引入。所以在学习的时候,我们就采用脚手架形式的安装。这就需要我们安装Node.js,用里边的npm来进行安装。

安装Node只需要进入Node网站,进行响应版本的下载,然后进行双击安装就可以了。

Node中文网址:http://nodejs.cn/ (建议你在这里下载,速度会快很多)

需要你注意的是,一定要正确下载对应版本,版本下载错误,可是没有办法使用的哦。

Node.js 安装好以后,如果是Windows系统,可以使用 Win+R打开运行,然后输入cmd,打开终端(或者叫命令行工具)。

输入代码:

node -v 

如果正确出现版本号,说明Node安装成功了,需要说明的是,你的版本号可能跟我视频中的有所不同,这无关紧要。

然后再输入代码:

npm -v

如果正确出现版本号,说明npm也是没问题的,这时候我们的Node.js安装就算完成了。

2、脚手架的安装

Node安装好之后,你就可以使用npm命令来安装脚手架工具了,方法很简单,只要打开终端,然后输入下面的命令就可以了。

npm install -g create-react-app

create-react-app是React官方出的脚手架工具,其实有很多第三方的脚手架工具,也有很多优秀的。但是作为初学者为了减少踩坑,所以我们使用官方的脚手架。

3、创建第一个React项目

脚手架安装好以后,就可以创建项目了,我们在D盘创建一个ReactDemo文件夹,然后进入这个文件夹,创建新的React项目。

D:  //进入D盘
mkdir ReactDemo  //创建ReactDemo文件夹
create-react-app demo01   //用脚手架创建React项目
cd demo01   //等创建完成后,进入项目目录
npm start   //预览项目,如果能正常打开,说明项目创建成功

报错解决备注:

npm install -g create-react-app
在mac上安装时,没有效果,使用了    cnpm install -g create-react-app

对应的在使用  create-react-app demo01 时,同样没有效果,此时应将cnpm设置为默认的安装方式
npm config set registry https://registry.npm.taobao.org

二、代码之路

import React,{Component} from 'react';
等价于 下面的两行(es6解构赋值)
import React from 'react';
const Component = React.Component

1、JSX简介

JSX就是Javascript和XML结合的一种格式。React发明了JSX,可以方便的利用HTML语法来创建虚拟DOM,当遇到<,JSX就当作HTML解析,遇到{就当JavaScript解析.

比如我们写一段JSX语法

<ul className="my-list">
    <li>JSPang.com</li>
    <li>I love React</li>
</ul>

比如我们以前写一段代码JS代码:

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

从代码量上就可以看出JSX语法大量简化了我们的工作。

2、组件和普通JSX语法区别

这个说起来也只有简单的一句话,就是你自定义的组件必须首写字母要进行大写,而JSX是小写字母开头的。
这个也算是一个比较重要的知识点吧。

注意: 这里的HTML类名 要用className定义,不能使用class

3、 JSX使用注意事项

在React中,最外层需要有一个包裹元素,最外层不想有包裹元素的话,使用<Fragment>标签。

要想使用<Fragment>,需要先进行引入。

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

然后把最外层的<div>标签,换成<Fragment>标签。

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

class Xiaojiejie extends Component{
    constructor (props) {
      super(props) //调用父类的构造函数,固定写法
      this.state = {
        inputValue: '',
        list: ['haha', '精油推背'],
        ceshiHTML:'<h1>ssss</h1>'
      }
    }
    render(){
        return  (
            <Fragment>
              {/* 正确注释的写法 */}
               <label htmlFor="jspang">加入服务:</label>
               <div><input id='jspang' /> <button> 增加服务 </button></div>
               <ul>
                   <li>头部按摩</li>
                   <li>精油推背</li>
                   <li dangerouslySetInnerHTML={{__html:this.state.ceshiHTML}}></li> 
               </ul> 
            </Fragment>
        )
    }
}
export default Xiaojiejie 

注意:
1、其实这边的写法,类似于Vue的组件写法,html必须有一个最外层html包裹;此时如果你不需要最外层的html,可以将最外层的html用Fragment代替,vscode不会报错,同时在html中也不会有最外层的html显示
2、jsx的注释写法,{/* 正确注释的写法 */}
3、HTML类名要把class换成className,它是防止和js中的class类名冲突
4、dangerouslySetInnerHTML={{__html:XX}},如果XX是含html标签的,则可以解析html标签;
5、label标签不能使用for。它容易和javascript里的for循环混淆,会提示你使用htmlFor。(想点击“加入服务”直接可以激活文本框,方便输入。按照html的原思想,是直接加ID就可以了)

4、方法定义以及使用

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

class Xiaojiejie extends Component{
  constructor (props) {
    super(props) //调用父类的构造函数,固定写法
    this.state = {
      inputValue: '',
      list: ['头部按摩', '精油推背']
    }
  }
  render() {
    return(
      <Fragment>
        <div>
          <input value = {this.state.inputValue} onChange={this.inputChange.bind(this)}/> 
          <button onClick={this.addList.bind(this)}> 增加服务 </button>
        </div>
        <ul>
            {
              this.state.list.map((item, index) => {
                return (
                  <li key={item + index}
                  onClick = {this.deleteItem.bind(this, index)}
                  > {item} </li>
                )
              })
            }
        </ul> 
    </Fragment>
    )
  }
  inputChange(e) {
    this.setState({
      inputValue: e.target.value
    })
  }
  addList(){
    this.setState({
      list: [...this.state.list, this.state.inputValue],
      inputValue: ''
    })
  }
  deleteItem(index){
    console.log(index)
    let list = this.state.list
    list.splice(index,1)
    this.setState({
      list: list
    })
  }
}
export default Xiaojiejie

注意:
1、onChange是一个change事件,在React里,事件的绑定要使用小驼峰命名法。
2、这里的.bind(this),是ES6的语法,此时里面需要绑定this,否则在方法中使用this时,this的指向并不是当前的dom元素。
3、React中的循环是写在{}中的,在循环中绑定方法的话,需要写在return()的括号中,此时若想要传值,和this一样写在.bind()中,在定义方法的时候,可以带参数,可以拿到。类似vue
4、React中对state里面的数据进行操作时,不能直接写this.state.XX = '',需要使用this.setState({XX:''})
5、React是禁止直接操作state的,即我们在删除this.state.list中的数据时,是将this.state.list赋值给一个新的数组,去操作这个新数据,最后将新数组的值赋值给this.state.list

5、父子组件之间的通信

  • 父组件
import React, { Component } from 'react';
// 这里的引入 FoodItem首字母要大写,不然会报错
import FoodItem from './foodItem'
import  './shitang.css'

class Shitang extends Component {
  constructor(props){
    super(props)
    this.state = {
      foodValue: '',
      foodList: ['土豆丝', '土豆片', '土豆块', '土豆泥']
    }
    this.addFood = this.addFood.bind(this)
    this.inputChange = this.inputChange.bind(this)
    this.deleteItem = this.deleteItem.bind(this)
  }
  render() { 
    return (  
      <div>
        <label htmlFor='food'>添加新菜品</label>
        <input
        id='food'
        vaule={this.state.foodValue}
        onChange={this.inputChange}
        // ES6语法 -- 绑定DOM元素
        ref={ input => {this.input = input}}></input>
        <button onClick={this.addFood}>添加菜品</button>
        <ul>
          {
            this.state.foodList.map((item, index) => {
              return (
                <li 
                key={item + index}
                // onClick={this.deleteItem(index)} --- 使用时会立即执行deleteItem方法
                onClick={() => this.deleteItem(index)}
                >{item}</li>
              )
            })
          }
        </ul>
        {/* 这里使用了子组件 FoodItem */}
        <ul className='food' ref = {ul => {this.ul = ul}}>
          {
            this.state.foodList.map((item, index) => {
              return (
                <FoodItem 
                key={item + index}
                content ={item}
                index = {index}
                onClick={() => this.deleteItem(index)}
                deleteItem = {this.deleteItem}
                />
              )
            })
          }
        </ul>
      </div>
    ); 
  }
  inputChange () {
    this.setState({
      foodValue: this.input.value
    })
  }
  addFood () {
    this.setState({
      foodList: [...this.state.foodList,this.state.foodValue]
    })
    console.log(this.ul.querySelectorAll('li').length)
    // 现象: 此时调用打印的值是与实际不相符的 
    // 原因: this.setState这个方法是异步的,当执行打印的时候,this.setState可能并没有执行完成
    // 解决方案: this.setState有一个回调函数,此时将打印放到回调函数中即可
    // this.setState({
    //   foodList: [...this.state.foodList,this.state.foodValue]
    // },() => {
    //   console.log(this.ul.querySelectorAll('li').length)
    // })
    this.input.value = ''
  }
  deleteItem (index) {
    let list = this.state.foodList
    list.splice(index, 1)
    this.setState({
      foodList: list
    })
  }
}
 
export default Shitang;
  • 子组件
import React, { Component } from 'react';
import PropTypes from 'prop-types'

class foodItem extends Component {
  constructor(props){
    super(props)
    this.deleteFood = this.deleteFood.bind(this)
  }
  render() { 
    return (  
      <li 
      onClick={this.deleteFood}
      >
      {this.props.username}--- 会做的菜 ---{this.props.content}
      </li>
    );
  }
  deleteFood () {
    this.props.deleteItem(this.props.index)
  }
}
// 校验传递值 PropTypes  使用时 需先引入
foodItem.propTypes ={
  // 必传值的校验 ---isRequired
  content:PropTypes.string.isRequired,
  deleteItem:PropTypes.func,
  index:PropTypes.number,
  username: PropTypes.string.isRequired
}
// 若设置必传值,又担心没有值则可使用默认值defaultProps;
// 此时若是父组件没有传递username这个参数,则会使用默认值渲染
foodItem.defaultProps = {
  username: '小花'
}
 
export default foodItem;
image.png

注意:
1、事件绑定的另一种写法:onClick={this.addFood.bind(this)} ====> onClick = {this.addFood};前面的写法是在绑定事件的时候将this指向一起绑定;后面的写法,this的指向是在constructor方法中绑定
this.addFood = this.addFood.bind(this)
2、在引入子组件时,子组件名称首字母要大写import FoodItem from './foodItem',否则会报错
3、在使用 onClick={this.deleteItem(index)}进行传参的时候,会立即执行deleteItem方法,并不是点击后触发deleteItem方法。修改为onClick={() => this.deleteItem(index)} 原因暂时不知道,但是这样可以解决
4、ref来绑定DOM元素:绑定时最好使用ES6语法中的箭头函数。 ref={ ul => {this.ul = ul}},此时需要注意:若此时我们想要获取ul下面li的个数,且li是动态生成的(addFood方法中),若是在this.setState()方法后执行,则会出现与实际不符的情况。 原因是this.setState()方法是异步加载的,当执行打印的时候,this.setState()可能并没有执行完成。解决方案:React的this.setState()方法提供了回调函数,写在回调中即可。
5、React有一个特性是单项数据流,即父组件向子组件传递一个数组的话,是可以传递成功的,但是这个数组在子组件中只可使用不可改变。
6、父组件向子组件传递参数和方法:在父组件中的子组件上传递(如下),传递的数据在子组件中用this.props.XXX接收,方法也一样

<FoodItem 
  key={item + index}
  content ={item}
  index = {index}
  onClick={() => this.deleteItem(index)}
  deleteItem = {this.deleteItem}
/>

7、在子组件中校验传递值( PropTypes) 使用时 需先引入import PropTypes from 'prop-types'

//foodItem --- 子组件的类名
foodItem.propTypes ={
  // 必传值的校验 ---isRequired
  content:PropTypes.string.isRequired,
  deleteItem:PropTypes.func,
  index:PropTypes.number,
  username: PropTypes.string.isRequired
}
// 若设置必传值,又担心没有值则可使用默认值defaultProps;
// 此时若是父组件没有传递username这个参数,则会使用默认值渲染
foodItem.defaultProps = {
  username: '小花'
}

8、子组件向父组件传递数据时,需要在子组件中使用this.props.xx(val)(其中val为需要传递给父组件的数据,可以为单个数据,也可以为对象的形式;xx表示在父组件中绑定的是方法名,这个方法在绑定之后也需要在父组件的constructor中使用bind()方法绑定this的指向)

6、react的生命周期

Initialization:初始化阶段。
Mounting: 挂载阶段。
Updation: 更新阶段。
Unmounting: 销毁阶段

image.png

备注:以上来自技术胖博主,以及自己的遇到的问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 作为一个合格的开发者,不要只满足于编写了可以运行的代码。而要了解代码背后的工作原理;不要只满足于自己的程序...
    六个周阅读 8,428评论 1 33
  • React简介 (1)简介 React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaSc...
    鱼鱼吃猫猫阅读 1,611评论 1 6
  • 40、React 什么是React?React 是一个用于构建用户界面的框架(采用的是MVC模式):集中处理VIE...
    萌妹撒阅读 1,005评论 0 1
  • 3. JSX JSX是对JavaScript语言的一个扩展语法, 用于生产React“元素”,建议在描述UI的时候...
    pixels阅读 2,810评论 0 24
  • [toc] REACT react :1.用来构建用户界面的 JAVASCRIPT 库2.react 专注于视图层...
    拨开云雾0521阅读 1,432评论 0 1