我的React笔记(1)

React:facebook团队开源

学习前提:js掌握,es6/7掌握

学习:React是最流行的,维护好,vue是最火的。

1.React中的核心概念

  • 虚拟dom
    • dom的本质:浏览器中的概念,用js对象来表示页面上的元素,提供操作dom的的api

    • 虚拟dom:框架中的概念,是程序员用js对象来模拟页面上的dom和dom嵌套(也就是虚拟手动模拟虚拟的dom树)

      var div = {
      	tagName:'',
           attrs:{},
      	childrens:{
      		'hhh',
      		{
      			tagName:'',
      			attrs:[],
      		    childrens:{
      				'ppp'
      			}
      		}
      	}
      }
      
    • 总结:虚拟dom的本质:就是用js对象的形式,来模拟页面上DOM元素和嵌套关系,(虚拟DOM是以js对象的形式存在的)

      目的:为了实现页面元素的高效更新。

  • Diff算法
    • tree diff :新旧两个dom树,逐层对比的过程。当对比完毕那么需要被更新的元素就可以找到。

    • component diff :在进行tree diff 的时候,每一层组件级别的对比。

      – 如果对比前后组建的类型相同,就暂时认为此组件不需要更新;如果对比前后的组件类型不同就移除旧组件,创建新组件,追加到页面中。

    • element diff:在进行组件对比的时候,如果两个组件的类型相同,就需要进行元素级别的对比。

2.Webpack 4.X基本配置

1,新建空文件夹,vs code打开
2,npm init -y 初始化
3, 创建 src  dist 文件夹
4, src中新建index.html,index.js
5, 装webpack 包 cnpm i webpack -D
   和cli(脚手架) cnpm i webpack-cli -D
6,webpack 4.x 提供了约定大于配置的概念,目的是为了尽量减少配置文件的提及
   根目录下新建 webpack.config.js
   在webpack.config.js里面设定好mode (必备) 
   就可以执行 webpack 进行打包了 (此时dist里面自动生成了一个main.js)
7, 但是只要修改了页面中的东西,每次都必须进行重新打包 为了方便 
   在安装 cnpm i  webpack-dev-server -D
   配置 package.json 中的scripts ->"dev": "webpack-dev-server"
   运行 npm run dev 就可以运行项目
8, 项目运行之后默认不是打开的项目首页,且重复读写indexhtml文件也会损伤磁盘
   所以安装 cnpm i html-webpack-plugin -D  在内存中生成虚拟的index.html
   安装之后,在webpack.config.js中配置
9, react项目中必须的几个插件 (此写法安装之后会出现babel版本冲突的问题,不再建议使用)
   cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
   cnpm i babel-preset-env babel-preset-stage-0 babel-preset-react -D
   cnpm i @babel/runtime -D
   修改之后的写法,安装的都是7.0以上的版本了
   cnpm i @babel/core babel-loader @babel/plugin-transform-runtime -D
   cnpm i @babel/preset-env @babel/preset-react -D
   安装之后首先在 webpack.config.js 中配置第三方的规则
   再 新建 .babelrc 文件 写入相应的presets和plugins
10,安装react相关,cnpm i react react-dom -S
11,根据需求安装相应的loader,配置第三方规则
"dev": "webpack-dev-server --open --port 3000 --hot --host 127.0.0.1 --progress --compress"
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const htmlPlugin = new HtmlWebpackPlugin({
    template:path.join(__dirname,'./src/index.html'),//源文件
    filename:'index.html'
})
module.exports = {
    mode: 'development',      // 模式配置
    plugins: [
        htmlPlugin
    ],
    module:{
        //第三方的loader
        rules:[
            {
                test : /\.js|jsx$/,
                use : 'babel-loader',
                exclude : /node_modules/
            }
        ]
    }
}

.babelrc文件内容(注意:此写法是低版本的写法,不建议采用,具体看下面的)

{
    "presets": [
        "env","stage-0","react"
    ],
    "plugins": [
        "transform-runtime"
    ]
}

在进行完上面的之后发现会因为babel版本问题导致项目运行失败,现修改为下面的版本

{
    "presets": [
        "@babel/react","@babel/env"
    ],
    "plugins": [
        "@babel/plugin-transform-runtime"
    ]
}

3.React中渲染DOM

  • 方法1
//这两个名称必须这样写
//cnpm i react react-dom -S
import React from 'react'   //创建组件 虚拟dom 生命周期
import ReactDOM from 'react-dom'   //创建好的组件 虚拟dom 放在页面上进行展示

//创建虚拟dom React.createElement
//参数 1:创建的元素的类型 字符串 表示当前元素的名称
//参数 2:是一个对象或者null 表示当前这个dom元素的属性
//参数 3:子节点 包括 文本子节点或者其他内嵌的元素
//参数 n:其他的子节点
const myH1 = React.createElement(
    'h1',
    {
        id:'myh1',
        title:'this is a h1'
    },
    '这是一个大大的h1'
)  //创建了

//使用reactdom进行渲染 ReactDOM.render
//参数 1:要被渲染的的虚拟dom元素
//参数 2: 指定页面上的一个进行承载的容器
ReactDOM.render(myH1,document.getElementById('app'))
  • 方法2
//jsx
//这两个名称必须这样写
import React from 'react'   //创建组件 虚拟dom 生命周期
import ReactDOM from 'react-dom'   //创建好的组件 虚拟dom 放在页面上进行展示

//创建虚拟dom
//在js中 默认是不可以 直接写html的代码
//所以这里使用babel进行转换
//这样在js里面写类似于html写的语言,叫做jsx 语法 是符合 xml的js
//本质就是 将下面的代码 直接转换为了 creatElement里面的东西
const myDiv = <div id="mydiv" title="this is a div">
                这是一个div
                <p>这是一个p元素</p>
              </div>

//使用reactdom进行渲染
//参数 1:要被渲染的的虚拟dom元素
//参数 2: 指定页面上的一个进行承载的容器
ReactDOM.render(myDiv,document.getElementById('app'))

jsx语法

当需要在jsx里面混合使用js表达式的时候,用{}包裹变量

let a = 10;let str = 'hhh';let boo = true;let title = 'divvv';
const h1 = <h1>我爱北京天安门</h1>;
let arr = [<h1>这是h1</h1>,<h2>这是h2</h2>]
let arrScore = [69,30,49,99]
<div title={title}> {a+1} <hr/> 这是{str} <hr/> {boo ? '真的':'假的'}
    {h1}  <hr/>
    {arr} <hr/>
    {arrScore.map(item=>item>60?'及格':'不及格')}
<div>

给元素添加class的时候要使用 className进行替代,label上的for属性,htmlFor进行替代

与Vue类似,必须有唯一的根元素进行包裹

4.React组件

  • //第一种创建组件的方法  构造函数
    //包括 给组件传递 数据 ,组件必须先接收参数,才能使用  只读
    function Hello(props){  //必须是 大写字母 开头
        //组件中必须 return 合法的jsx 虚拟dom元素。 如果return null 那就是表明该组件什么也不渲染
        return <h1>ppp---{props.name}---{props.age}</h1>
        //组件中的props都是只读的,不能再这里面重新赋值
    }
    const dog = {name:'red',age:1};
    ReactDOM.render(<div><Hello name='yellow' age={dog.age}></Hello></div>,document.getElementById('app'))
    
  • //第二种创建组件的方法 class
    //在class 创建的组件中,传递的参数不需接收,可以直接使用 this.props.XXX进行访问  只读
    class 组件名称 extends React.Component{
      	constructor(){
            super();
            this.state = {  //自己的私有属性 this.state就相当于 vue中的data(){return {}}  可读可写
                msg:'我是state里面的msg'
            }
      	 }
        render(){
            this.state.msg = '我修改了state里面的msg'
            //render里面必须返回合法的jsx虚拟dom结构 或是 null
            return <div>123456 {this.props.XXX}---<p>{this.state.msg}</p></div>
        }
    }
    const M1 = {XXX:xxx}
    ReactDOM.render(<div><Movie {...M1}></Movie></div>,document.getElementById('app'));
    
    对比两种创建组建的方式
    1. 使用 class关键字创建的组件,除了有只读的props,还有自己的生命周期和可读可写的私有数据(this.state);但是function创建的只有只读的props

    2. 使用 构造函数 function 创建的组件,叫做“无状态组件”

      使用 class 创建的组件,叫做“有状态组件”

      注意:当 一个组件 需要有自己的私有数据,就使用class创建;反之亦然

      ​ 官方说:无状态组件的运行效率会高一些,但是还是推荐使用class创建有状态组件~~~

    3. 组件中的props 和 state区别

      props:外界传递过来的数据,只读

      state :组件私有的数据,一般是ajax获取到的,可读可写

5.React中使用Style、css样式

  • ​ style 行内样式

    ​ 注意:字符串类型 样式值 要使用引号包裹 ;数值类型 直接写

    <h1 style = {{color:'red',fontSize:'35px',zIndex:2}}></h1>
    //可以与组件定义写在一个jsx页面中,或者可以单独写在一个style.js文件中,在jsx页面中import进来使用
    const itemStyle = { style1:{color:'red',fontSize:'35px',zIndex:2}
                      style2:{}}; 
    <h1 style = {itemStyle.style1}></h1>
    
  • ​ css 样式

    .title{
        color:red;
        font-size: 35px;
        text-align: center;
    }
    
    import from '@/css/cmtList.css';//这样导入的样式表,一般在整个项目中都生效,所以要对laoder进行配置
    <h1 className="classname">评论列表</h1>
    

    注意:要安装第三方loader才能解析 css文件 cnpm i style-loader css-loader -D

    ​ 并在webpack.config.js的modules—rules中进行配置

    test:/\.css$/,
    use:[
         {loader:'style-loader'},
         {loader:'css-loader'}
        ]
    

    第三方的css文件一般使用这种方法
    对于自己定义的样式表,我们一般使用 scss文件
    安装loader : cnpm i sass-loader node-loader -D
    并配置模块化:

    test:/\.scss$/,
    use:[
        {loader:'style-loader'},
        {loader:'css-loader',
         options:{
         modules:{
         localIdentName:'[path][name]_[local]--[hash:base64:5]SS'}
         }},
         {loader:'sass-loader'}
        ]
    

    项目中使用方法
    import xxxobj from ‘路径’
    className={xxxobj.classname}

6.React绑定事件

 export default class BindEvent extends React.Component{
    constructor(){
        super();
        this.state={}
        //下面这句可以不写,如果你的函数不需要使用到this,只是简单地alert或者console。
        this.myclickhandler=this.myclickhandler.band(this);
    }

    render(){
        return <div>点击事件
            <hr/>
            <button className="btn btn-primary" onClick={this.myclickhandler}>按键</button>
        </div>;
    }

    myclickhandler(){
        console.log('222222222')
        this.setState(preState=>{
            ... ...
        })
    }
}
  • 事件处理的名称是react提供的,必须使用驼峰式。

  • 事件处理函数的格式 onClick = {function}

  • 用的较多的事件绑定的写法

    <button onClick={()=> this.show('参数')}></button>
    show = (arg1) =>{
        console.log('showff'+arg1);
    }
    
  • 修改state中的数据,使用的是this.setState({})

7.React的生命周期

  • 生命周期:每个组件的实例,从创建,运行直到销毁的过程中发生的一些事件。

  • React的生命周期分为以下三个过程

    • 组件创建阶段:一辈子只执行一次

      componentWillMount
      render
      componentDidMount

    • 组件运行阶段:按需运行0到无数次

      componentWillReceiveProps
      shouldComponentUpdate
      compponentWillUpdate
      render
      componentDidUpdate

    • 组件销毁阶段:一辈子只执行一次

      componentWillUnmount
      img

8.状态提升

在 React 应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state 都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。

也就是说,几个组件需要共同使用到的数据,可放在他们的父组件上,方便使用。

这里涉及到了父子之间的问题。

父子传值----props

props不仅可以是数据,还可以是对象,是函数

//子
class InputTemp extends React.Component{
    constructor(props){
        super(props);
        this.state={
        }
    }

    handlerChange=(e)=>{//看看子是怎么使用父的方法的,使用挂载在props上的方法即可
        this.props.SaveTemp(e.target.value);
    }

    render(){
        return (<div>
            <input value={this.props.temp} onChange={(e)=>this.handlerChange(e)}/>{this.props.unit}
        </div>);        
    }
}
//父
class Calculator extends React.Component{
    constructor(props){
        super(props);
        this.state={
            InputTemptext:'',
            type:'c'
        }
    }

    saveCelsius=(temperature)=>{
        this.setState({
            InputTemptext:temperature,
            type:'c'
        })
    }

    saveFahrenheit=(temperature)=>{
        this.setState({
            InputTemptext:temperature,
            type:'f'
        })
    }

    render(){
        const temperature  = this.state.InputTemptext;

        const celsius = this.state.type === 'c' ? temperature : tryConvert(temperature,toCelsius);
        const Fahrenheit = this.state.type === 'f' ? temperature : tryConvert(temperature,toFahrenheit);
        
        return (<div>
            <fieldset>
            <legend>Enter temperature in Celsius:</legend>
            <InputTemp unit="Celsius" temp={celsius} saveTemp={(arg)=>this.saveCelsius(arg)}></InputTemp>  {/*数据和对象甚至函数都挂载到子组件上去*/}
            <InputTemp unit="Fahrenheit" temp={Fahrenheit} saveTemp={(arg)=>this.saveFahrenheit(arg)}></InputTemp>
            </fieldset>
            <BoilingVerdict temp={parseFloat(celsius)}></BoilingVerdict>
        </div>)
    }
}

9.错误边界用法

错误边界可以处理–渲染的错误,将错误的渲染ui替换为备用的(wrong 提示)

首先要使用class组件创建出 ErrorBoundary组件,用它将其他的组件进行包裹,被包裹的组件出现内部错误的时候就会被渲染为 ErrorBoundary组件 ->“备用ui”

注意

错误边界无法捕获以下场景中产生的错误:

  • 事件处理(了解更多)(使用try-catch)
  • 异步代码(例如 setTimeoutrequestAnimationFrame 回调函数)
  • 服务端渲染
  • 它自身抛出来的错误(并非它的子组件,自身内跟普通代码一样用try…catch…)

10.React-router-dom

npm install react-router-dom

在.jsx的组件文件中,这样写即可

import React from 'react';
import {HashRouter,Route,Link} from 'react-router-dom'   //导入!!!!!
//HashRouter 表示一个路由的根容器,将来所有的路由相关的东西,都将包裹在内,而且一个网站中,只需要使用一次
//Route 表示一个路由规则,在Route上,有两个比较重要的属性,path component
//Link 表示一个路由的链接,就相当于 vue中的 <router-link to=""></router-link>
import Home from './components/home.jsx'
import Movie from './components/Movie.jsx'
import About from './components/About.jsx'
export default class App extends React.Component{
    constructor(props){
        super(props);
        this.state={}
    }

    render(){
        //使用hashrouter将组件内容包裹之后,就已经启用路由了,可以发现网站路径多了#
        //在一个hashrouter里面 只能有唯一的子结点
        return (<HashRouter><div>
                <h1>这是app组件的内容,现在是三个路由导航</h1>
                <Link to="/home">首页</Link>&nbsp;&nbsp;&nbsp;
                <Link to="/movie">电影</Link>&nbsp;&nbsp;&nbsp;
                <Link to="/about">关于</Link>&nbsp;&nbsp;&nbsp;
                <hr/>
                <Route path="/home" component={Home}></Route>
                <Route path="/movie" component={Movie}></Route>
                <Route path="/about" component={About}></Route>
                </div></HashRouter>)
    }
}

Route标签:1,表示路由匹配的规则 2,表示占位符(类似vue里的router-view)

注意

  • 默认情况下,路由中的规则是模糊匹配的,如果部分的路由可以匹配成功,就展示这个路由(Route里面的path对应的)对应的组件

    如果希望路由规则进行精确匹配可以为Route添加 exact属性, 这时候link和Route匹配不对应就不会展示该组件

    如果希望展示,可以使用参数匹配,使用 :修饰符。 Route的path改为 ‘/movie/:type/:id’

  • 想获取路由规则中,匹配到的参数,可以使用 this.props.match.params.***进行获取

    或者 将props.match.params放在this.state内使用。

    this.state={routeParams:this.props.match.params}
    //使用的时候  this.state.routeParams.id  获取id参数,(似乎实际在使用的时候有bug)
    

11.Hook

在介绍组件的两种方式的时候,有说明,使用function构造的组件是没有自己的state的,但是如果将当遇到突然要添加自己的state的时候,一般的做法是–将function改写成class方法。

但是现在可以使用 hook ,可以为组件添加自己的state。(hook只能使用在非class得地方)

  • useState

使用方法:

import React ,{useState} from 'react';
(export default) function Hello (){
    const [count,setCount] = useSate(0);//声明一个叫count的state变量,初始值count = 0;
    //useSate方法的返回值,当前 state 以及更新 state 的函数
    //必须成对使用[something, setSomething] =》类似于class中的state和setState
    return (<div>
        <p>你点击了{count}</p>
        <button onClick={()=>setCount(count + 1)}>点击</button>
        </div>)
}
  • useEffect

useEffect可以看作是 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合。(点击跳转

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值