• react 基础知识(一)


    1、 安装1 (版本 react 18)

    // 安装全局脚手架(create-react-app基于webpack+es6)
    npm install -g create-react-app
    //使用脚手架搭建项目
    create-react-app my-app
    // 打开目录
    cd my-app
    // 运行项目
    npm start
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    目录结构

    2、初体验

    import React from 'react';
    // 17写法
    import ReactDOM from 'react-dom';
    const root = document.getElementById('root');
    ReactDOM.render(<App />, root);
    // 18写法
    import ReactDOM from 'react-dom/client';
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <h1>hello</h1>
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3、JSX(javascript+xml的语法)

    概念:jsx是js和html混合的语法,将组件结构、数据、样式聚合在一起定义组件,会编译成普通的js

    • 遇到 < 开头,用html规则解析(标签必须闭合
    • 遇到 { 开头,用js规则解析
    • 样式style等于一个对象(属性使用驼峰式命名)
    • 声明类名用clssName=类名,因为class是js关键字
    export default function App() {
      return (
        <div className="App">
        // { }里面是js表达式(变量的运算符组合,如a+b),必须返回一个值
          {
            arr.map(function(item,index){
            // 渲染后为style="background-color:green"
              return <span style={{backgroundColor:'green'}} className='read_name' key={index}>{item}</span>
              
            })
          }
        </div>
      );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 判断使用三目运算符、if、&&
      注: 勿将数字放在 && 左侧 {num&& < A />} 当num=0时,会渲染0
    // 三目运算	{flag?  : } 表示 “当 flag为真值时, 渲染 ,否则 ”。
    return <span style={{backgroundColor:index==0?'green':"pink"}} >张三</span>
    // if判断	选择性返回jsx
    if(flag){return <h1>张三 √</h1>}
    return <h1>张三 </h1>
    // &&	{flag&& } 表示 “当 flag为真值时, 渲染 ,否则不渲染”
    return (
      <h1>
        张三 {flag&& '✔'}
      </h1>
    );
    
    • 渲染列表用map,filter可以筛选需要的组件
      循环列表时必须添加key值
    // map遍历见上示例
    // filter 示例
    arr=[{name:'张三',age:20},{name:'李四',age:10}]
    let newArr=arr.filter(item=>item.age>18)
    
    • 1
    • 2
    • 3
    • 4

    jsx中使用js的规则:

    • 引号包含的值作为字符串传递
    • {} 包含js 逻辑与变量
    • {{}} 表示包含的是一个js对象
    • 它们在内容区域属性= 后面生效

    4、组件

    页面分割成多个组件,每个组件有自己的逻辑与样式,不同组件可组合成一个新的页面。可组合、可重用、可维护
    组件类第一个字母必须大写,只能包含一个顶层标签可用div或者是空标签<>包起来
    注:凡是首字母小写都会被识别为react元素(html标签)

    (1)声明组件(导出-声明-添加)
    // 第一步:导出组件 export default  一个文件只能有一个default
    // 第二步:声明组件   function App(){}
    export default function App() {
    // 第三步:添加标签
    // return 与标签不在一行,必须用()b包起来,否则什么都不会返回
      return (
        <div className="App">hello</div>
      );
      // 或写成一行
      // return  
    hello
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    (2)导入与导出

    同一文件中,有且仅有一个默认导出,但可以有多个具名导出
    图解

    (3)创建组件的2种方式

    第一种:函数式声明 ,function App(){} 静态组件,见(1)示例
    第二种:类名组件 class App extends Component{}

    import React,{Component } from 'react';
    export default class App extends Component {
      // render 指该组件如何渲染,一定要返回一个react元素,且只能有一个根元素
      render(){
        return <h1>hello</h1>
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5、props(父子组件传参)

    • 传递props,需要将参数加到jsx中
    • 读取props,可使用function App({name,id})的解构语法
    • 可以指定默认值,函数式声明直接用name=“李四”,class声明用static defaultProps={name:‘李四’}
    //1、函数式的demo
    // 这里使用结构取出name,也可写成props.name
    function Child({name}) { 
    //可以给name附初始值 name="李四",当调用时没有传值,会使用默认值
    // function Child({name="李四"}) { 
      return (
        <span>{name}</span>
      );
    }
    export default function App() {
      return (
        <div className="App">
          <Child name="张三"></Child>
      </div>
      );  
    }
    // 2、class类的demo
    class Children extends Component{
      static defaultProps={name:'李四'} // 默认属性值,即父类调用不传递props,会使用这个默认的值
      render(){
        return(
          <h1>{this.props.name}</h1>
        )
      }
    }
    export default class App extends Component {  
      render(){
        return (
          <div>
            <Children name="张三"></Children>
            <Children ></Children> {/* 未传值会显示默认值“李四” */}
          </div>
        )
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • class声明的组件可以使用prop-types指定props的类型和是否必填
    // 第一步安装插件
    npm install props-types -S 安装依赖
    // 引入PropTypes 
    import PropTypes from 'prop-types' 
    class Children extends Component{
     // 定义组件的类型和是否必传
     static propTypes={
       name:PropTypes.string, // name类型为string
       age:PropTypes.number.isRequired // age   number,且必填
     }
     render(){
       return(
         <div>
           <h1>{this.props.name}</h1>
           <div>年龄:{this.props.age}</div>
         </div>
       )
     }
    }
    export default class App extends Component {
     render(){
       return (
         <div>
           {/* 错误写法 */}
           <Children name={1}></Children>
           {/*会提示报错,The prop `age` is marked as required in `Children`, but its value is `undefined`.
           Invalid  prop `name` of type `number` supplied to `Children`, expected `string`*/}
           
           {/* 正确写法 */}
           <Children name="张三" age={1}></Children>
         </div>
       )
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    prop-types 常用类型 :array、bool、func、object、number、string、symbol、element
    限制必要:PropTypes.类型.isRequired
    仅限制必要:PropTypes. any.isRequired
    多种类型:PropTypes.oneOfType([[PropTypes.string,PropTypes.number ])
    多可选类型:PropTypes.oneOf([‘张三’,‘李四’])
    特定结构对象:PropTypes.shape({name:类型,age:类型})

    // 多种类型--以下代码就不会报错
     static propTypes={
        name:PropTypes.oneOfType([PropTypes.string,PropTypes.number]),
      }
    <Children name={1}></Children>
    // 多选类型--只能传递red和blue中的一个值,否则会报错,不能不传
    static propTypes={
        color:PropTypes.oneOf(['red','blue']),
      }
     <Children color="red"></Children>  
     // 特定结构对象, 符合结构的才可以
     static propTypes={
        obj:PropTypes.shape({
            name: PropTypes.string.isRequired,
            age: PropTypes.number.isRequired
        })
      } // 符合obj={name:'xxx',age:数字}
      <Children obj={{name:'张三',age:14}}></Children>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • props是只读,不可被修改
    • 像< Card>< Avatar />< /Card>这样的嵌套 JSX,将被视为 Card 组件的 children prop (类似于插槽)
    function Card({ children }) {
      return (
        <div className="card">
          {children}
        </div>
      );
    }
    
    export default function App() {
      return (
        <Card>
          <Avatar
            size={100}
            person={{ 
              name: 'Katsuko Saruhashi',
              imageId: 'YfeOqp2'
            }}
          />
        </Card>
      );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    6、状态state和事件处理

    (1)state状态:组件内部变化的值
    import React,{Component } from 'react';
    export default class App extends Component {
      constructor(){
        super();
        this.state={name:'张三'}  // 自定义组件状态对象(组件内部变化的值,内部初始化内部改变)
      }
      // 生命周期函数   组件挂载完成
      componentDidMount(){
        // 调用setState ,状态会更新,还会重新调用render方法重新渲染
        this.setState({name:'李四'})
      }
      render(){
        return <h1>{this.state.name}</h1>
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    setState是异步,不能在赋值后立即获取新state,可在其回调函数中获取

    // 会先打印修改前的值,再打印修改后的值
    handleClick=()=>{
            this.setState({
                num:this.state.num+1
            },()=>{
                console.log("获取修改后的值",this.state.num)
            })
            console.log("获取修改前的值",this.state.num)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    (2)事件处理:

    class声明-----onClick={this.方法名}
    function声明-----onClick={方法名}

    // class声明onClick={this.方法名} 
    export default class App extends Component {
      constructor(){
        super();
        this.state={heart:true}  
      }
      handleClick=()=>{
        this.setState({heart:!this.state.heart})
      }
      render(){
        return (
          <div>
            <span>心情{this.state.heart?'开心':'伤心'}</span>
            <button onClick={this.handleClick}>变心</button>
          </div>
        )
      }
    }
    // 函数式声明:onClick={方法名}--无实例无this
    export default function App(){
        const handleClick=()=>{
            console.log('dianji')
        }
        return(
            <>
            <button onClick={handleClick}>点击</button>
            </>
        )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    7、表单组件的双向绑定、refs

    (1)双向绑定

    受控组件:受当前组件的状态控制
    非受控组件:不受当前组件状态控制

    export default class App extends Component{
        constructor(){
            super()
            this.state={name:'张三'}
        }
        handleChange=(event)=>{
            // 通过获取输入框的值实现双向绑定
            this.setState({name:event.target.value})
        }
        render(){
            return (
            <div>
                <div>hello,{this.state.name}</div>
                {/* 受控组件,必须加change事件 */}
                <input onChange={this.handleChange} value={this.state.name}></input>
                {/* 非受控组件,随便输 */}
                <input onChange={this.handleChange} ></input>
            </div>
            )
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    (2)refs:可获取DOM元素及其实例

    class有三种(refs字符串、 refs回调函数、createRef)、

    // class声明有实例,所以可以用字符串refs|回调函数|createRef()三种方式,以下是示例
    export default class App extends Component{
        constructor(){
            super()
            this.myRef=React.createRef() // 3、createRef方式
        }
        handleChange=(event)=>{
            console.log(this.refs.test.value,'方式一:已废弃')
            console.log(this.b.value,'方式二:回调函数')
            console.log(this.myRef.current.value,'方式三:createRef,获取元素是.current')
        }
        render(){
            return (
            <div  onChange={this.handleChange}>
                {/* refs--字符串方式,已经被废弃,使用会被浏览器警告 */}
                <input ref="test"></input>
                {/* refs--回调函数,会执行2次,一次传参null,一次传参dom元素 */}
                <input ref={ref=>this.b=ref}></input>
                {/* refs--createRef方式,dom元素为.current属性*/}
                <input  ref={this.myRef}></input>
            </div>
            )
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    function也有三种(useRef、React.forwardRef、React.useImperativeHandle)

    // 因为function没有实例,所以不能用class的三种refs的方式
    // 方式一:useRef,.current获取组件实例
    export default function App(){
        const myRef=useRef(null)
        const handleClick=()=>{
            myRef.current.focus()
        }
        return(
            <>
            <input type="text" ref={myRef} />
            <button onClick={handleClick}>点击聚焦</button>
            </>
        )
    }
    // 方式二:forwardRef,该ref绑定的值是组件内ref绑定的节点而非组件实例,组件实例是不可以访问该回调ref函数
    import React, { Component, forwardRef} from 'react';
    const Test=forwardRef(function (props,ref){
        return <h1 ref={ref}></h1>
    })
    export default class App extends Component{
        constructor(){
            super()
            this.myRef=null
        }
        handleClick=()=>{
            this.myRef.innerHTML="加油哦"
        }
        render(){
            return (
            <div>
                <Test type="text" ref={ref=>this.myRef=ref} />
                <button onClick={this.handleClick}>点击聚焦</button>
            </div>
            )
        }
    }
    //方式三:useImperativeHandle,结合forwardRef使用
    const Test=forwardRef(function (props,ref){
        const inputRef = React.useRef();
        React.useImperativeHandle(ref, () => ({
            focus: () => {
                inputRef.current.focus();
            },
        }));
        return <input ref={inputRef }/>
    })
    export default class App extends Component{
        constructor(){
            super()
            this.myRef=null
        }
        handleClick=()=>{
            this.myRef.focus()
        }
        render(){
            return (
            <div>
                <Test type="text" ref={ref=>this.myRef=ref} />
                <button onClick={this.handleClick}>点击聚焦</button>
            </div>
            )
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    8、组件的生命周期

    (1)class声明才有生命周期

    声明周期图
    声明周期执行示例:

    export default class App extends Component{
        constructor(){
            super()
            this.state={num:0}
            console.log('constructor:初始化')
        }
        static getDerivedStateFromProps(){
            console.log('getDerivedStateFromProps:组件即将加载或发现state、props变化')
            return null
        }
        handleClick=()=>{
            console.log('准备变值')
            this.setState({
                num:this.state.num+1
            },()=>{
                console.log("获取修改后的值",this.state.num)
            })
        }
        shouldComponentUpdate(newProps,newState){
            console.log('shouldComponentUpdate:是否应该变化')
            return !newState.num%5==0
        }
        getSnapshotBeforeUpdate(){
            console.log('getSnapshotBeforeUpdate:将要更新')
            return null
        }
        componentDidUpdate(){
            console.log('componentDidUpdate:更新结束')
        }
        render(){
            console.log('render:组件开始挂载')
            return (
            <div>
                <p>{this.state.num}</p>
                <button onClick={this.handleClick}>点击聚焦</button>
            </div>
            )
        }
        componentDidMount(){
            console.log('componentDidMount:组件挂载完成')
        }
        componentWillUnmount(){
            console.log('componentWillUnmount:卸载前')
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    挂载更新
    注:componentWillMount、componentWillUpdate、componentWillReceiveProps已经被官方废弃,请尽量用上图的生命周期函数

    (2)函数式声明没有生命周期,一般用useEffect替代

    其作用同componentDidMount、componentDidUpdate、componentWillUnmount

    export default function App(){
        const [num, setNum] = useState(0);
        const [num1, setNum1] = useState(1)
        // 1、useEffect 第二个参数为空useEffect(()=>{}),初始化渲染之后执行一次,当页面所有数据变化时也会执行一遍,同componentDidMount、componentDidUpdate,-----初始化执行、点击按钮1和2都会执行
        // 2、useEffect 第二个参数为空数组useEffect(()=>{},[]),初始化渲染render之后只执行一次,数据变化不执行,同componentDidMount---初始化执行、点击按钮1、2不执行
        // 3、useEffect 第二个参数为监听值,useEffect(()=>{},[num]),初始化渲染render之后执行一次,监听元素变化执行一次,同componentDidMount、componentDidUpdate----初始化执行、点击按钮2才会执行
        useEffect(()=>{
            console.log('useEffect')
        },[num1])
        // 4、useEffect 第一个函数返回一个函数,表示在组件卸载前执行,同componentWillUnmount  useEffect(()=>{return ()=> {// 在此走一些收尾工作,如清除定时器/取消订阅等}},[stateValue])
        return(
            <>
            <p>{num}</p>
            <button onClick={()=>setNum(num+1)}>点击1</button>
            <p>{num1}</p>
            <button onClick={()=>setNum1(num1+1)}>点击2</button>
            </>
        )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1. 若安装脚手架时报以下错,将npm切换成淘宝镜像即可安装成功
      报错截图 ↩︎

  • 相关阅读:
    SAP 让ALV表格修改后保存到数据库(1.设置图标事件;2.LVC_S_GLAY-EDT_CLL_CB字段直接实现)
    振弦式测缝(位移)计表面裂缝监测
    Vue 响应式实现原理深入浅出
    Word处理控件Aspose.Words功能演示:使用 Python 保护 Word 文档
    算法27:最长公共子序列——样本模型(4)
    安装node.js后进行的操作(配置node环境变量、npm镜像加速、安装vue-cli项目脚手架、在IDEA中打开并运行脚手架)
    java计算机毕业设计Vue框架电商后台管理系统MyBatis+系统+LW文档+源码+调试部署
    ssm框架之spring:xml如何配置创建对象
    新零售模式这么应用,太牛了
    JAVA PowerMock 单元测试
  • 原文地址:https://blog.csdn.net/sinat_34626741/article/details/130621564