React的基本介绍

    更新时间: 2022-10-15 20:57:36
    点击量: 660
    标签: 前端jsreact

    简介:构建React是为了解决一个问题:使用随时间变化的数据构建大型应用程序, React中页面也是组件

    文章均为个人原创, 搬运请附上原文地址感谢, 原文来自MasterYi博客

    React介绍

    • 构建React是为了解决一个问题:使用随时间变化的数据构建大型应用程序, React中页面也是组件
    • MVVM的核心就是简化dom操作, 数据决定视图变化, React的核心就是围绕两个数据: state(内部维护的状态值) 和 props(父组件传递的值);
    • React 中,数据仅朝一个方向流动,即从父组件流向子组件。如果数据在兄弟子组件之间共享,那么数据应该存储在父组件,并同时传递给需要数据的两个子组件; (当然这里会有人存疑,使用redux状态管理,子组件内改变状态,父组件也能更新啊,因为组件都在根节点拿的数据,本身不存在往上流的问题 )
    • React 是使用JSX创建虚拟DOM, 在将虚拟DOM元素渲染到页面中的真实容器DOM中显示。

    这里是一张介绍组件化开发的图,和以前的划分区域模块写代码差不多,只不过组件化的标准使得组合更加的清晰,模块更具有独立性; 尤其体现在一些大型工程时,你会有一种汽车的那种零件化标准的感觉 img.png

    JSX基本语法规则

    • 定义虚拟DOM时,不要写引号。
      • 标签中混入JS表达式时要用 { }。
      • 样式的类名指定不要用 class,要用 className。(因为class是ES6中类的关键字,所以不让用)
      • 内联样式,要用 style={{ key:value }} 的形式去写。
      • 只有一个根标签; 标签必须闭合

    class组件

    渲染类组件标签的基本流程

    • React内部会创建组件实例对象
    • 调用render()得到虚拟DOM, 并解析为真实DOM
    • 插入到指定的页面元素内部

    state & setState

    • state组件的状态值,也有一种说法叫组件的记忆,把视图需要依赖变化的值存储起来
    • constructor() 是唯一直接设置 this.state 的地方,其它地方都通过 setState() 方法来设置 state;
    • state 的更新是异步的,且是一个合并的过程
    • setState: 用户更新数据,重新渲染dom元素。调用setState,react会将传入的参数和当前组件的状态合并,然后出发调和过程,经过调和过程,react会以高效的方式根据新的状态构建react元素树,并重新渲染界面。react构建树之后,react会计算出新树和老树的节点差异,然后根据差异进行界面最小化的渲染
    class demo extends React.Component{
        
        constructor(props) {
            super(props)
            // 原state为:
            this.state = {
                title: ' ReactJs ',
                content: 'React is an wondefun JS  library'
            }
        }
        
        onClick(){
            // 当只需要修改title时, 将修改的title传给setState即可
            this.setState({ title: 'Good' })
            // react会合并最新的title到原来的状态,同时保留原来状态的content,最终合并state为
            // {
            //     title:'Good',
            //     content:'React is an wondefun JS  library'
            // }
        }
        
        return(){
            return <>
                {JSON.stringify(this.state)}
                <button onClick={() => this.onClick()}>改变title</button>
            </>
        }
    }

    props

    • 是由父组件传递给子组件
    • 值可以是数据、函数、组件;
    • 不可变更;
    class deom extends React.Component{
        // 父组件
        constructor(props) {
            super(props)
            this.state = {
                name: 'Tom'
                person: [
                    { id: 1, name: 'zs', age: 18},
                    { id: 2, name: 'ls', age: 19}
                ]
            }
        }
        
        render(){
            return <Test 
                name={this.state.name} 
                onClick={() => this.setState({ name: this.state.name === 'Tom' ? 'Jack' : 'Tom' })} 
                person={this.state.person}
            />
        }
    }
    
    // 子组件Test
    interface IProps { // 接收从父组件传来的属性及函数
        name: string
        onClick: () => void
        person: Array<{ id: number, name: string, age: number }>
    }
    
    class Test extends React.Component<IProps>{
        render(){
            return <>
                <button onClick={() => this.props.onClick()}>点击修改名字</button>
                <h1>name: {this.props.name} </h1>
            </>
        }
    }

    生命周期

    图例解释

    生命周期:指的是组件从初始化开始到结束的过程 或者是生命周期是描述ract组件从开始到结束的过程
    钩子函数:指的是系统某些状态和参数发生改变的时候,系统立马去通知对应处理的函数 叫做钩子函数

    • constroctor(props): 类的构造函数,组件被创建时,首先会调用组件的构造方法。
      • 接收一个props参数,必须调用super(props)才能保证被传入组件中;
      • 初始化组件的state
    • render():初始化渲染或更新渲染调用 (该方法是所有生命周期方法中必须实现的方法。该方法的作用就如它的名字一样 —— 渲染)
    • componentDidMount(): 组件挂载完成(开启监听, 发送请求)
    • componentWillUnmount(): 组件即将卸载(清理定时器)

    函数式组件

    • 使用js的函数创建组件
    • 函数名称必须以大写字母开头
    • 函数组件必须有返回值,表示该组件的
    • 如果返回值为null,表示不渲染任何内容
        // 1. 创建函数式组件 
        // 传统函数写法
        function MyComponent(){
            console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
            return <span>我是用函数定义的组件(适用于简单组件的定义)</span>
        }
    
        // 箭头函数写法
        const MyComponent = () => {
            return (
                <div>
                    <span>
                        我是用函数定义的组件(适用于简单组件的定义)
                    </span>
                </div>
            )
        }

    函数式组件(Hooks)

    useState 状态

        // hook useState 简单使用
        // count 代表state 的值, setCount 则是更新count 的 setState 方法, useState(初始值)
        const [count, setCount] = useState(1)
        // useState 方法会有默认类型推导 , 如果有复杂类型,且初始值为未定义再使用定义
        const [user, setUser] = useState<IUserInfo>(undefined)

    useEffect

    • 传入两个值, 第一个值callback, 第二值为依赖的响应值列表,响应式值包括 props、state 以及所有直接在组件内部声明的变量和函数

    • 依赖是指,如果依赖的值发生了改变, 此副作用将会被再次调用,
    • 依赖值为数组, 可填入多个依赖, 有一个发生变化则会变化, 如果依赖值不传, 则内部使用的变量数据变化副作用也会被重新调用
    const IndexPage: FC<IProps> = (props) => {
        // hook useState 简单使用
        const [count, setCount] = useState(1)
        // hooks useEffect 的挂载注销使用, 务必要加后方的空依赖
        useEffect(() => {
            console.log(`组件挂载`)
            return () => {
                console.log(`组件注销`)
            }
        }, [])
    
        // hooks useEffect 如果不指定依赖, 内部使用的值变化了,也会被重新调用
        useEffect(() => {
            console.log(`count 变了后的副作用`, count)
        })
    
        return <>
            <div>
                <button className={styles.btn} onClick={() => setCount(count + 1)}>点击改变count, 测试 useEffect 的调用
                </button>
            </div>
        </>;
    }

    useCallback

    • 传入两个值, 第一个值callback, 第二值为依赖响应式值包括 props、state,和所有在你组件内部直接声明的变量和函数

    • 此处的依赖与 useEffect 异曲同工, 但是有一个最大的不同, useEffect 是指变化后执行函数, useCallback是变化后更新函数
    • 因为callback创建的函数中使用的 state,props ,会永远保持依赖最后一次更新的样子
    • 当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染的子组件时,它将非常有用。 并不是啥时候都要用,随便用就是负优化了
    const IndexPage: FC<{ content: string, parks: any }> = (props) => {
        // hook useState 简单使用
        const [count, setCount] = useState(1)
    
        // 无依赖的useCallback, 内部使用的state, 会永远保持最初的状态
        const func_a = useCallback(() => {
            console.log('func_a: count', count)
        }, [])
    
        // 依赖于count
        const func_b = useCallback(() => {
            console.log('func_b: count', count)
        }, [count])
    
        return <>
            <div>
                <button onClick={() => {
                    setCount(count + 1);
                }}>count+1 : {count}</button>
            </div>
            <div>
                <button onClick={() => func_a()}>func_a</button>
            </div>
            <div>
                <button onClick={() => func_b()}>func_b</button>
            </div>
        </>;
    }

    本篇到此结束了,只是简单的介绍一下React的两种编写方式,至于Context、高阶组件、自定义hook、memo、ref后续文章再一一介绍