react

226 阅读9分钟
安装 html-webpack-plugin 的原因
1、帮我们把代码生成到内存中去,因为webpack自动打包的文件是生成在物理磁盘上的,这样很消耗性能
2、在浏览器中输入localhost:8080默认不会打开首页
3、需要在首页中引入打包好的js文件
html-webpack-pluginwebpack.config.js 文件中去配置

配置完成之后,在index.html中不需要引入打包好的js文件
在浏览器中输入localhost:8080之后,会默认自动打开首页

在项目中使用react

  1. 运行npm i react react-dom -S 安装包

    • react:专门用于创建组件和虚拟DOM的,同时组件的生命周期都包在这个包中
    • react-dom:专门用于DOM操作,最主要的场景就是ReactDOM.render()
  2. index.html 页面中,创建容器:

    • 使用React创建的虚拟DOM元素,都会被渲染到这个指定的容器中
      <div id="app"></div>
      
  3. index.js 中导入包

如果要在h1标签外面嵌套div该怎么实现呢?

JSX语法

什么是JSX语法:就是符合xml规范的js语法(语法格式相对来说,要比HTML严谨很多)

  1. 如何启用jsx语法?
    • 安装 babel 插件
      • 运行 npm i babel-core babel-loader babel-plugin-transform-runtime -D
      • 运行 npm i babel-preset-env babel-preset-stage-0 -D
      • 在webpack.config.js文件中添加第三方匹配规则
    • 安装能够识别转换jsx语法的包 babel-preset-react
      • 运行 npm i babel-preset-react -D
    • 添加 .babelrc 配置文件 *

JSX语法注意事项

  • 在jsx中写注释:推荐使用 { /*注释内容*/ }
  • 为jsx中的元素添加class类名:需要使用 className 来代替 class htmlFor 替换label 的for属性(注意:是标签上面的for属性)
  • 在jsx创建DOM的时候,所有的节点,必须有唯一的根元素进行包裹
  • 在jsx中标签必须成对出现,如果是单标签需要自闭和

当编译引擎,在编译jsx代码的时候,如果遇到了 < 那么就把它当作html代码去编译,如果遇到 {} 就把{}内部的代码当作普通js代码去编译

创建组件,并为组件传递props数据

方式一:(注意:组件的名称都需要以大写字母开头)

// 创建组件的第一种方式
function Hello(props) {
    console.log(props);
    return <div>这是Hello组件==== {props.name} </div>
}
let data = {
    name:'aaa',
    age:30
}
ReactDOM.render(<div>
    {/* 直接把组件的名称,以标签的形式丢到页面上就好 */}
    <Hello name={data.name} age={data.age}></Hello>
</div>,document.getElementById('app'))

方式二:(将组件抽离为单独的.jsx文件)

// Hello.jsx文件
// 创建组件的第二种方式
export default function Hello(props) {
    console.log(props);
    return <div>这是Hello组件==== {props.name} </div>
}

// 在index.js 文件中引入
import Hello from './components/Hello.jsx';
ReactDOM.render(<div>
    {/* 直接把组件的名称,以标签的形式丢到页面上就好 */}
    <Hello name={data.name} age={data.age}></Hello>
</div>,document.getElementById('app'))
  • 注意一:

    • 文件引入的时候,默认不能省略 .jsx 后缀,如果想要省略,则需要事先在webpack.config.js文件中去配置

class讲解:(使用es6中新增的class关键字)

  1. 首先创建一个 .jsx 的文件

  2. class Animal {
        // 类的构造器,每一个类中都有一个构造器
        // 如果程序员没有手动指定构造器,那么则可以认为,类内容中有个隐形,的看不见的空构造器 类似于 constructor(){}
        // 构造器的作用:每当 new这个类的时候,必然会优先执行构造器中的代码
    
        // 在构造器中通过this分配的属性,可以称为实例属性
        // 注意1:在class的 {} 区间内,只能写构造器,静态属性,静态方法,实例方法
        // 不能 var a = 10 这样的语法会报错
        
        // 注意2:class关键字内部,还是用原来的构造函数来实现的
        constructor(name,age) {
            this.name = name;
            this.age = age;
        }
        // 静态属性【在class内部,通过static修饰的属性,就是静态属性】
        static info = '我是静态属性'
    	 // 实例方法
        sihli() {
            console.log('我是挂载到原型对象上的实例方法');
        }
        // 静态方法
        static s_shili() {
            console.log('我是静态方法');
        }
    }
    
    
    const a1 = new Animal('小黄',30); // 创建一个实例对象,并且传递参数
    
    console.log('class创建的组件',a1)
    console.log('访问静态属性',Animal.info)
    // console.log('实例方法的访问',a1.sihli)
    a1.sihli()
    // 访问静态方法
    
    Animal.s_shili();
    

extends与super介绍

class Person {
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
    sayHi() {
        console.log('你好,我是Person类中的方法')
    }
}


class Child extends Person{
    constructor(name,age) {
        // 问题一:为什么一定要在constructor中调用super
        // ------ 如果一个子类,通过extends关键字继承父类,那么在子类的constructor构造函数中,必须优先调用一下super()
        // 问题二:super是什么?
        // ------- super是一个函数,而且,它是父类的构造器,子类的super其实就是父类中,constructor构造器中的一个引用
        // 问题三:为什么调用super之后,child实例的name和age都变成了underfined
        super()
    }
}
const child = new Child('Jacqui',21);
child.sayHi();
console.log('===',child.name,child.age)

方法二:(使用class关键字,创建组件,并接收外界传递过来的参数)

// 使用class关键字,创建组件

class Movie extends React.Component {
    // render 函数的作用是渲染当前组件  对应的虚拟DOM元素
    // 另一个问题:render属于class的实例方法

    // 在class关键字,创建的组件中,如果想使用外界传递过来的 props参数,不需要接收,直接this.props.xxx访问即可
    render() {
        // 注意:在class组件内部,this表示当前组件的实例对象
        return <div>我是使用class关键字创建的组件--- { this.props.name } </div>
    }
}

ReactDOM.render(<div>
    {/* 这里的Movie标签,其实就是Movie 类 的一个实例对象 */}
    <Movie {...data}></Movie>
</div>,document.getElementById('app'))

class关键字创建的组件,接收外界传递过来的参数,不需要接收,直接使用 this.props.xxx

两种创建组件方式对比

注意一:使用class关键字创建的组件,有自己的私有数据**(this.state)**和生命周期函数

注意二:使用function创建的组件,没有自己的私有数据和生命周期函数

  1. 构造函数创建出来的组件,叫做 无状态组件
  2. class关键字 创建出来的组件,叫做 有状态组件
  3. 组件中的 propsstate/data 之间的区别
    • props中的数据是只读的,不能重新赋值
    • state/data中的数据,都是可读可写的
    • props中的数据,都是外界传递过来的
    • state/data中的数据,都是组件私有的(通过Ajax获取回来的数据,一般都是私有数据)
  4. 什么情况下使用有状态组件,什么情况下使用无状态组件?
    • React官方说:无状态组件,由于没有自己的state和生命周期函数,所以运行效率会比有状态组件稍微高一些

有状态组件和无状态组件的本质区别

有无state属性 有无生命周期函数

应用案例:
  • function Child_cmList(props) {
        return  <div>
                    <h1>评论人:{props.user}</h1>
                    <div>评论内容:{props.content}</div>
                </div>
    }
    class CmtList_parent extends React.Component {
        constructor() {
            super()
            this.state = {
                CommonList: [
                    {id:1, user:'张三',content:'内容1'},
                    {id:2, user:'李四',content:'内容2'},
                    {id:3, user:'王五',content:'内容3'},
                    {id:4, user:'麻子',content:'内容4'},
                    {id:5, user:'sss',content:'内容5'},
                    {id:6, user:'Jack',content:'内容6'}
                ]
            }
        }
        render() {
           return <div>
               <h1>评论列表标题</h1>
               {this.state.CommonList.map(item => 
                    // <div key={item.id}>
                    //     <h1>评论人:{item.user}</h1>
                    //     <div>评论内容:{item.content}</div>
                    // </div>
                    <Child_cmList {...item} key={item.id}></Child_cmList>
                   
                )} 
           </div>  
        }
    }
    ReactDOM.render(<div>
       <CmtList_parent></CmtList_parent>
    </div>,document.getElementById('app'))
    

React行内样式的写法

// 方式一:
<h1 style={{ color:'#f00',textAlign:'center',fontSize:'35px'  }}>评论列表标题</h1>

// 方式二:
const h1Style = { color:'#f00',textAlign:'center',fontSize:'35px'  }
<h1 style={h1Style}>评论列表标题</h1>

// 方式三:抽离为单独的 样式表 模块 ==》把样式单独封装成一个样式对象 .jsx 文件
export default item = {
	h1Style:{color:'#f00',textAlign:'center',fontSize:'35px' }	
} 

import Style from 'style.jsx'
<h1 style={Style.h1Style}>评论列表标题</h1>

webpack默认无法打包 .css 文件

  • 安装插件 npm i style-loader css-loader -D

React样式表作用域冲突的问题

为普通样式表通过modules参数启用模块化

css模块化 只针对 类选择器id选择器 生效

css模块化 不会将标签选择器模块化

使用 localIdentName 自定义生成的类名的格式,可选的参数有:

  • [path] 表示样式表 相对于项目根目录 所在的路径

  • [name] 表示样式表文件名称

  • [local] 表示样式的类名定义名称

  • [hash:length] 表示32位的hash值

  • { test: /\.css$/,use:['style-loader','css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]']},
    

元素有多个类名

// 方式一
<h1 className={变量 + ' text'}></h1>

// 方式二
<h1 className={[变量, 'text'].join(' ')}></h1>

// 后面写 .join(' ');  的原因,因为在页面上渲染的时候,类和类之间使用 , 分割的, 

如何让类名不被模块化(:global())

注意一:被 :global()包裹起来的类名,不会被模块化,而是全局生效

注意二:被 :local() 包裹起来的类名,会被模块化,默认所有的类名和Id选择器,都被模块化了

// 方式一:在 xx.css

:global(.test) {
    color:#0f0;
}

使用第三方样式表

  1. 安装 Bootstrap npm i bootstrap@3.3.7 -S
在项目中启用模块化,并同时使用Bootstrap,会出现问题,如果模块化启用,第三方样式文件类名也会被模块化,所以为了避免这种情况,自己的样式文件写  scss 或者 less

React中绑定事件注意点

  1. 事件的名称都是React提供的,因此名称的首字母 必须大写 onClick onMouseOver

  2. 为事件提供的处理函数,必须是如下格式

    onClick = {function}
    
    // 方式一:
    <button onClick={this.myClick}>My Name Is Button</button>
    
    // 与render平级,定义一个 myClick 方法
    myClick() {
        console.log('点击了按钮')
    }
    
    // 注意:方式一的写法,没办法传递参数
    
    // 方式二
    <button onClick={() => {this.myClick('张三')}}>My Name Is Button</button>
    
    myClick(name) {
        console.log(name+'点击了按钮')
    }
    
    // 方式三:将箭头函数简化
    <button onClick={ () =>this.myClick('张三')  }>My Name Is Button</button>
    
    myClick =(name)=>{
         console.log(name+'点击了按钮')
    } 
    

修改state上的数据

// 注意:在React中想要修改state中的值,不能用下面的写法
  this.state.msg = name; // 错误写法

// 正确写法: this.setState({msg:'123'})
  this.setState({ // 这个方法是异步的
      msg:name
  })

  this.setState({ // 这个方法是异步的
      msg:name
  },()=> {
      console.log('因为this.setState这个方法的执行是异步的,如果想要获取最新的值:',this.state.msg)
  })

代码一旦被注释,无法折叠,使用下面的写法能解决这一问题

//#region
// 被注释的内容
//#endregion