React笔记

本文介绍了React的基础知识,包括全局安装脚手架、创建项目、JSX语法、组件创建、事件绑定、状态管理和生命周期。讲解了如何使用函数和类创建组件,以及如何处理this指向问题。还涉及了React中的样式渲染、组件通信、受控与非受控组件的概念,最后探讨了Hooks的使用,如useState和useEffect,以及路由的基本应用。

# 全局安装脚手架

npm i create-react-app -g

创建项目:

# project-name 项目名称

create-react-app react-demo

src/index.js:

// 导入 react [核心语法包]

import React from "react";

// 导入 react-dom [react操作DOM的模块包]

import ReactDOM from "react-dom";

// <h1 id='desc'>你好</h1>
// 1. 创建react虚拟DOM元素 React.createElement(标签名,属性,内容)
const h1 = React.createElement('h1', { id: 'desc' }, '你好')

// 2. 将react元素挂载到对应节点上 ReactDOM.render(渲染的react元素,挂载节点,回调)
ReactDOM.render(h1, document.getElementById('root'))

JSX: javascript xml 是React.createElement的语法糖 帮我们做了编译, 可以使创建元素更加简单,更加直观,提高开发效率。

// 语法点
// 1. 使用{变量/表达式} 渲染数据
// ===> 对象不能直接渲染
// ===> 布尔值渲染不出来, 但是作为判断是可以的
// 2. 标签必须要闭合(注意单标签)
// 3. 注释写法: {/* 注释内容 */}
// 4. 一些标签的属性发送了变化
// ===> class变成className
// ===> label的for属性 变成 htmlFor
// ===> 多个单词组成的属性要变成驼峰命名
// 5. 标签的嵌套一定要符合严格语法要求
// 6. 属性绑定 < 标签 属性={变量} 属性={'字符串'+变量} >
// 7. 一个JSX片段建议使用()包裹
// 8. 一个JSX片段必须只有一个根标签
// ===> <> 包裹元素 </>
// ===> <React.Fragment> 包裹元素 </React.Fragment>

 JSX渲染数组 会将数组每个元素取出进行渲染

样式渲染:

// 语法:
// < 标签 style={ 样式描述对象 } />
// < 标签 style={ {css属性名:"css属性值"} } />

React 创建组件:

  1. 使用函数 function
  2. 使用类 class
  • 语法约定
    • 函数名称首字母必需大写,React 据此来区分组件和 HTML 元素
    • 函数必须有返回值,表示该组件的 UI 结构,如果不渲染任何内容可返回null

回顾 class 语法定义类属性和函数,回顾 extends 语法继承父类:

// 回顾类的知识点
// ES5中, 定义类使用的是 构造函数 函数首字母大写
// ES6中, 定义类使用的是 关键字class

class Animal {
    top = '我是动物类'
    say = function () {
        console.log('我会说话===动物类');
    }
}

class Dog extends Animal {
    // 类的成员属性
    type = '狗类'
    // 类的成员方法
    skill = function () {
        console.log('我会看家');
    }

    // 类的静态属性(不会变)
    // static desc = '这是狗类的描述'
    // // 类的静态方法
    // static run = function () {
    //     console.log('狗会跑');
    // }

}
Dog.desc = '这是狗类的描述111'
Dog.run = function () {
    console.log('狗会跑111');
}

let d = new Dog()
console.log(d);
d.skill()
console.log('=====================');
// 静态属性和方法需要通过类名去调用
console.log(Dog.desc);
Dog.run()

类组件-定义状态:

  • 定义state属性定义组件状态,属于组件自己的数据,它的值是个对象。
  • 使用state的时候通过this去访问即可,例如:this.state.xxx
  • 数据发生变化,驱动视图更新。
// 一定要有render函数 返回JSX片段 会自动调用
 // 状态数据定义在state属性里面
    // state数据改变 render也会重新调用

快捷键:rcc

事件绑定用on事件名, 事件名第一个字母要大写

this指向的解决方式:

  constructor() {
        super()
        // 方式2: 在构造函数里面使用bind将this绑定
        this.fn3 = this.fn3.bind(this)
    }
    // 定义状态
    state = {
        count: 100
    }
    // 事件函数
    fn1() {
        console.log('fn1');
        console.log(this); // undefined
    }
    fn2() {
        console.log('fn2');
        console.log(this); // 当前组件
    }
    fn3() {
        console.log('fn3');
        console.log(this); // 当前组件
    }
    fn4() {
        console.log('fn4');
        console.log(this); // 当前组件
    }
    // 方式4 定义事件函数的时候就定义成箭头函数
    fn5 = () => {
        console.log('fn5');
        console.log(this); // 当前组件
    }

  render() {
        return (
            <div>
                <h3>App组件</h3>
                <p>count的数据是{this.state.count}</p>
                <button onClick={this.fn1}>点击+10</button>

                {/* 方式1: 模板里面使用bind将this绑定 */}
                <button onClick={this.fn2.bind(this)}>点击+10</button>

                {/* 方式2: 构造函数里面bind绑定 */}
                <button onClick={this.fn3}>点击+10</button>

                {/* 方式3: 模板里面定义箭头函数 箭头函数可以留存this的指向不变化 */}
                <button onClick={() => { this.fn4() }}>点击+10</button>

                {/* 方式4: 定义事件函数的时候就定义成箭头函数 */}
                <button onClick={this.fn5}>点击+10</button>
            </div>
        )
    }

既传参又获取事件对象:


    // 定义状态
    state = {
        count: 100
    }
    // 事件函数
    fn2(num, event) {
        event.preventDefault()
        console.log(event);
        console.log(num);
        console.log('fn2');
        console.log(this); // 当前组件
    }
    fn4(num, event) {
        event.preventDefault()
        console.log(event);
        console.log(num);
        console.log('fn4');
        console.log(this); // 当前组件
    }

  render() {
        return (
            <div>
                <h3>App组件</h3>
                <p>count的数据是{this.state.count}</p>

                <a href="" onClick={this.fn2.bind(this, 10)}>点击+10</a>

                <a href="" onClick={(event) => { this.fn4(20, event) }}>点击+20</a>
            </div>
        )
    }

修改state数据:

  // setState方法调用之后, 会让render函数重新执行, 实现页面更新

        this.setState({ count: 200 })

  // render里面不要写setState方法 否则会出现死循环

受控组件和非受控组件( 没有被state控制的表单原生认为是非受控组件 )

非受控组件表单绑定:

  // createRef表示用于创建一个引用对象, 类似ref的作用

 constructor() {
        super()
        // 1. 创建引用对象
        this.mobileRef = createRef()
        this.passwordRef = createRef()
    }

  // this.引用对象.current 表示获取到了对应的DOM节点

绑定: ref={this.mobileRef}

组件通信:

父直接在子上面传

const Hello = (props) => {
    // 函数式组件, 形参是props数据
    console.log(props);
    return (
        <div>
            <h3>Hello</h3>
            <p>{props.msg}==={props.num}</p>
            {props.title}
        </div>
    )
}

export default class Hi extends Component {
    render() {
        console.log(this.props); // 父子通信的数据
        console.log(this.props.state);
        this.props.fn()
        return (
            <div>
                <h3>Hi</h3>
                <p>{this.props.desc}</p>
            </div>
        )
    }
}

可以用解构直接传进去: <Item key={item.id} {...item} />

生命周期:

// 创建期: constructor==>render==>componentDidMount[挂载完成, 一般做ajax请求或者初始化插件, 类似vue的mounted]

// 更新期: render==>componentDidUpdate[每次数据state或props更新都会执行]

// 销毁期: componentWillUnmount[组件将要卸载时触发, 清除定时器]

// 实现插槽的2种方式:
// 方式1: 父子通信 传递JSX片段
// 方式2: 组件标签之间放内容, props.children访问

 props校验:

// 定义校验的静态属性
List.propTypes = {
    // 属性名: 校验函数
    // 属性名: 校验函数.isRequired  // 必须要传入
    colors:PropTypes.array,
    num:PropTypes.number.isRequired
}
List.defaultProps={
    msg:'我是msg的默认值'
}

 static propTypes = {
      title:PropTypes.oneOfType([PropTypes.number,PropTypes.string]).isRequired,
      sex:PropTypes.oneOf(['男','女'])
  }
static defaultProps={
    ok:'我是默认的ok'
}

Hooks:

 // Hooks 只用在函数组件 提供状态
    // 作用: useState是给函数组件提供状态
    // 使用: useState(初始值)
    // 返回 一个数组, 第一个元素时定义的状态, 第二个元素时修改数据的方法
    const [msg, setMsg] = useState('你好Hooks')
    // msg 是定义的状态数据变量
    // setMsg 是修改状态的方法, setMsg( 新值 )

 修改:

const changeList1 = () => {
        list.splice(0, 1, 'haha')
        // setList(list) 这样不更新, 地址没有改变
        setList([...list])
    }

useEffect:


    // useEffect( ()=>{ 逻辑代码 },[变量] )
    // 类似监听器的作用, 当变量发送变化的时候, 才会执行逻辑代码
    useEffect(() => {
        console.log("count的数值是:" + count);
        document.title = `点了${count}次`
    }, [count])

    // useEffect( ()=>{ 逻辑代码 },[ ] ) 依赖空数组
    // 类似 compentDidMount 挂载完成之后
    useEffect(() => {
        window.addEventListener('resize', () => {
            console.log('尺寸调整了');
        })
    }, []) // 页面更新时
    useEffect(() => {
        console.log('发送请求');
    }, []) // 页面一打开时

// useEffect 副作用

// 渲染之外的操作都称之为副作用

  /* useEffect( ()=>{

        逻辑代码

        return ()=>{

            销毁的时候要做的事情

        }

    },[])

    // 类似componentWillUnMount

    */

// const [变量, 修改方法] = useState(初始值)

// 修改数据方法1: 修改方法( 新值 ) ====> 合并策略

// 修改数据方法2: 修改方法( 老值=>新值) ====> 每个都执行

路由:

import { HashRouter, NavLink, Route, Switch, Redirect } from 'react-router-dom'
// 路由模式组件: BrowserRouter(history模式路由) / HashRouter(hash模式路由) 顶层标签, 所有路由组件在其内部
// 导航链接组件: NavLink  导航用到, 涉及到高亮激活的 <NavLink to="/地址"></NavLink>
// 普通链接组件: Link   普通的跳转标签 <Link to="/地址"></Link>
// 路由映射组件: Route  建立组件和地址之间的关系 
// ==>优先级 低 <Route path="/地址" component={组件}></Route>
// ==>优先级 高 <Route path="/地址"><组件/></Route>
// exact严格模式
// 匹配跳出组件 Switch 从上往下匹配, 匹配到了就跳出, 不继续匹配了
// 重定向组件 Redirect <Redirect to="/地址" />

// 导入页面组件
// import Home from './views/Home'
// import News from './views/News'
// import Product from './views/Product'
// import User from './views/User'
// import NotFound from './views/NotFound'
// import NewsDetail from './views/News/detail'
// import ProductDetail from './views/Product/detail'
// import Login from './views/Login'
// 路由懒加载
//  React.lazy(() => import(组件路径))

 

导航守卫:

// 导航守卫 定义一个权限组件
const AuthRoute = (props) => {
  if (localStorage.getItem('USER-TOKEN')) {
    // 登录, 正常渲染
    return <Route {...props}>{props.children}</Route>
  } else {
    // 未登录, 渲染Redirect
    return <Redirect to="/login" />
  }
}

 路由信息钩子:

import {useParams,useHistory} from 'react-router-dom'

 

antd组件库:

表单:

  {/* 登录表单 */}
        {/* Form组件上的validateTrigger属性是设置表单校验的时机, 默认是onChange变化的时候 */}
        {/* Form组件上的initialValues={{key:val,key2:val2}} 表示表单的初始值 */}
        {/* Form.Item组件上的valuePropName是取哪个属性的值作为数据 默认是value */}
        <Form validateTrigger={["onChange","onBlur"]} autoComplete="off">
            <Form.Item name="mobile" rules={formRuels.mobile}>
            <Input prefix={<UserOutlined/>} placeholder="请输入手机号" />
            </Form.Item>
            <Form.Item name="code" rules={formRuels.code}>
            <Input prefix={<LockOutlined/>} placeholder="请输入验证码" />
            </Form.Item>
            <Form.Item name="isAgree" valuePropName="checked">
            <Checkbox>我已阅读并同意「用户协议」和「隐私条款」</Checkbox>
            </Form.Item>
            <Form.Item>
            <Button type="primary" block>
                登录
             </Button>
            </Form.Item>
        </Form>

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值