React基础

一、简介

1.官网

英文官网:http:// https://reactjs.org/

中文官网:https://react.docschina.org/

2.介绍

  1. 用于动态构建用户界面的 JavaScript (只关注于视图)
  2. Facebook开源

3.React高效的原因

  1. 使用虚拟(virtual)DOM, 不总是直接操作页面真实DOM
  2. DOM Diffing算法, 最小化页面重绘

4.相关js

  1. react.jsReact核心库。
  2. react-dom.js:提供操作DOMreact扩展库。
  3. babel.min.js:解析JSX语法代码转为JS代码的库。

5.创建虚拟DOM的两种方式

  1. JS方式(一般不用)
  2. JSX方式

使用JS方式

 <!-- 准备好一个容器 -->
    <div id="test">
    </div>
    <!-- 1.先引入react核心库 -->
    <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
    <!-- 2.再引入react-dom,用于react操作dom -->
    <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
    <script type="text/babel">/* 此处一定要写 */
        // 1.创建虚拟dom
        // const VDOM = React.createElement(标签名,标签属性,标签内容)
        const VDOM = React.createElement('h1', { id: 'title' }, React.createElement('span', {}, 'Hello,React'))
        // 2.渲染虚拟dom到页面
        // ReactDom.render(虚拟Dom,容器)
        ReactDOM.render(VDOM, document.getElementById('test'))
    </script>

使用JSX

 <!-- 准备好一个容器 -->
    <div id="test">
    </div>
    <!-- 1.先引入react核心库 -->
    <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
    <!-- 2.再引入react-dom,用于react操作dom -->
    <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
    <!-- 3.引入babel,用于将jsx转为js -->
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
    <script type="text/babel">/* 此处一定要写 */
        // 1.创建虚拟dom
        const VDOM = (/* 此处一定不要写引号,因为不是字符串 */
            <h1 id="title">
                <span>Hello,React</span>
            </h1>
        )
        // 2.渲染虚拟dom到页面
        // ReactDom.render(虚拟Dom,容器)
        ReactDOM.render(VDOM, document.getElementById('test'))
    </script>

二、JSX

全称:  JavaScript XML

react定义的一种类似于XMLJS扩展语法: JS + XML本质是 React.createElement(componentprops, ...children)方法的语法糖

作用: 用来简化创建虚拟DOM

  1. 写法:var ele = <h1>Hello JSX!</h1>
  2. 它不是字符串, 也不是HTML/XML标签

  3. 它最终产生的就是一个JS对象

基本语法规则:

  1. 定义虚拟dom时,不需要写引号。
  2. 标签中混入js表达式时要用{}。
  3. 样式的类名不要用class,用className。

  4. 内联样式,要用style={{key:value}}的形式去写。

  5. 虚拟dom只有一个跟标签。

  6. 标签必须闭合。

  7. 标签首字母:

    (1).若小写字母开头,则将该标签转为html中同名元素,若html无该标签对应的同名元素则报错。(2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。

bable.js的作用:

  1. 浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
  2. 只要用了JSX,都要加上type="text/babel", 声明需要babel来处理

例子:

 <!-- 准备一个容器 -->
    <div id="test"></div>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
    <script type="text/babel">
        const myId = 'aTgUiGu'
        const myData = 'Hello,rEact'
        // 1.创建虚拟dom
        const VDOM = (
            <div>
                <h2 id={myId.toLocaleLowerCase()} className="title">
                    <span style={{color:'white',fontSize:'20px'}}>{myData.toLocaleLowerCase()}</span>
                </h2>
                <input/>
            </div>
        )
        // 2.渲染虚拟dom的页面
        ReactDOM.render(VDOM,document.getElementById('test'))
    </script>

一定注意区分:【js语句(js代码)】与【js表达式】

表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方,下面这些都是表达式:

  • a

  • a+b

  • demo(1)

  • arr.map()

  • function test () {}

语句(代码):

  • if(){}

  • for(){}

  • switch(){case:xxxx}

三、组件

1.组件分类

(1)函数式组件

函数式组件即函数定义的组件。

例如:

  <div id="test"></div>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
    <script type="text/babel">
        // 1.创建函数式组件
        function Demo(){
            console.log(this);//此处的this是undefined,因为babel编译后开启了严格模式
            return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
        }
        // 2.渲染组件到页面
        ReactDOM.render(<Demo/>,document.getElementById('test'))
        /*
            执行了ReactDOM.render(<Demo/>......之后,发生了什么?
                1.react会解析组件标签,找到了Demo组件
                2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟dom转为真是dom,随后呈现到页面中
        */
    </script>

(2)类式组件

例如:

<div id="test"></div>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
    <script type="text/babel">
        // 1.创建类式组件
        class Mycomponent extends React.Component {
            render() {
                // render是放在那里的? 类的原型对象上,供实例使用。
                // render的this是谁? Mycomponent的实例对象。<=> Mycomponent组件实例对象
                return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
            }
        }
        // 2.渲染组件到页面
        ReactDOM.render(<Mycomponent/>,document.getElementById('test'))
        /*
            1.react会解析组件标签,找到了Mycomponent组件
            2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用的原型上的render方法。
            3.将虚拟dom转为真实dom,随后呈现在页面中。
        */
    </script>

注意点:

  1. 组件名必须首字母大写
  2. 虚拟DOM元素只能有一个根元素
  3. 虚拟DOM元素必须有结束标签

基本流程:

  1. React内部会创建组件实例对象

  2. 调用render()得到虚拟DOM, 并解析为真实DOM
  3. 插入到指定的页面元素内部

2.组件的三大核心

(1)state

state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)

组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

用法案例:

<div id="test"></div>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
    <script type="text/babel">
        class Weather extends React.Component{
            // 初始化状态
            state = {isHot:true}
            render(){
                const {isHot} = this.state
                return <h1 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h1>
            }
            // 自定义方法   要用赋值语句的形式+箭头函数
            changeWeather = ()=>{
                const isHot = this.state.isHot
                this.setState({isHot:!isHot})
            }
        }
        ReactDOM.render(<Weather/>,document.getElementById('test'))
    </script>

注意:

  1. 组件中render方法中的this为组件实例对象。
  2. 状态数据,不能直接修改或更新,需要使用setState方法修改。

(2)props

每个组件对象都会有props(properties的简写)属性

组件标签的所有属性都保存在props

作用:通过标签属性从组件外向组件内传递变化的数据

注意: 组件内部不要修改props数据,在函数是组件中只能使用组件三大核心中的props。

用法:

  1. 内部读取某个属性值this.props.name

  2. props中的属性值进行类型限制和必要性限制

第一种方式(React v15.5 开始已弃用):

Person.propTypes = {
 name: React.PropTypes.string.isRequired,
 age: React.PropTypes.number
}

第二种方式(新):使用prop-types库进限制(需要引入prop-types库)

Person.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number. 
}

        3. 扩展属性: 将对象的所有属性通过props传递 :<Person {...person}/>

        4. 默认属性值:

Person.defaultProps = {
  age: 18,
  sex:'男'
}

        5. 组件类的构造函数

constructor(props){
  super(props)
  console.log(props)//打印所有属性
}

 例如:

<div id="test"></div>
    <div id="test1"></div>
    <div id="test2"></div>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签进行限制 -->
    <script src="../js/prop-types.js"></script>
    <script type="text/babel">
        // 创建组件
        class Person extends React.Component {
            // 对标签属性进行类型、必要性限制
            static propTypes = {
            name:PropTypes.string.isRequired, // 指定name为字符串类型且必传
            age:PropTypes.number,   // 指定age为数字类型
            sex:PropTypes.string,   // 指定sex为字符串类型
            speak:PropType.func   // 指定speak为函数类型
            }
            // 设置默认值
            static defaultProps = {
                sex:'男',
                age:18
            }
            render(){
                const {name,age,sex} = this.props
                // props是只读的
                // this.props.name = 'jack'    // 此行代码会报错,因为props是只读的
                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{sex}</li>
                        <li>年龄:{age}</li>
                    </ul>
                )
            }
        }
        // 渲染组件
        ReactDOM.render(<Person name="tom" sex="女" age={18} speak={speak}/>,document.getElementById('test'))
        ReactDOM.render(<Person name="jerry" sex="男" age={19}/>,document.getElementById('test1'))
        const p = {name:'老刘',age:18,sex:'女'}
        ReactDOM.render(<Person {...p}/>,document.getElementById('test2'))
        function speak(){
            console.log('我说话了');
        }
    </script>

 (3)refs

组件内的标签可以定义ref属性来标识自己

用法:

  1. 字符串形式的ref:<input ref="input1"/>
  2. 回调形式的ref:<input ref={(c)=>{this.input1 = c}(开发常用)

  3. createRef创建ref容器
myRef = React.createRef() 
<input ref={this.myRef}/>

案例:

字符串形式

<script type="text/babel">
        // 创建组件
        class Demo extends React.Component {
            showData = () => {
                let { input1 } = this.refs
                alert(input1.value)
            }
            showData1 = () => {
                let { input2 } = this.refs
                alert(input2.value)
            }
            render() {
                return (
                    <div>
                        <input type="text" placeholder="点击按钮提示数据" ref="input1" />
                        <button onClick={this.showData} ref="button100">点我提示左侧输入框数据</button>
                        <input type="text" placeholder="失去焦点提示数据提示数据" ref="input2" onBlur={this.showData1} />
                    </div>
                )
            }
        }
        // 渲染组件
        ReactDOM.render(<Demo />, document.getElementById('test'))
    </script>

回调形式

<script type="text/babel">
        // 创建组件
        class Demo extends React.Component {
            showData = () => {
                let { input1 } = this
                alert(input1.value)
            }
            showData1 = () => {
                let { input2 } = this
                alert(input2.value)
            }
            render() {
                return (
                    <div>
                        <input ref={c => this.input1 = c} type="text" placeholder="点击按钮提示数据" />
                        <button onClick={this.showData}>点我提示左侧输入框数据</button>
                        <input type="text" placeholder="失去焦点提示数据提示数据" onBlur={this.showData1} ref={c => this.input2 = c} />
                    </div>
                )
            }
        }
        // 渲染组件
        ReactDOM.render(<Demo />, document.getElementById('test'))
    </script>

createRef创建ref容器

<script type="text/babel">
        // 创建组件
        class Demo extends React.Component {
            // React.createRef()调用后可以反会一个容器,该容器可以存储ref所标识的节点,该容器是专人专用的
            myRef = React.createRef()
            myRef2 = React.createRef()
            showData = () => {
                alert(this.myRef.current.value);
            }
            showData1 = () => {
                alert(this.myRef2.current.value)
            }
            render() {
                return (
                    <div>
                        <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
                        <button onClick={this.showData}>点我提示左侧输入框数据</button>
                        <input type="text" placeholder="失去焦点提示数据提示数据" onBlur={this.showData1} ref={this.myRef2} />
                    </div>
                )
            }
        }
        // 渲染组件
        ReactDOM.render(<Demo />, document.getElementById('test'))
    </script>

3.包含表单的组件分类

(1)受控组件

<script type="text/babel">
      class Login extends React.Component{
        state = {
            username:'',
            password:''
        }
        saveUsername = (event)=>{
            this.setState({username:event.target.value})
        }
        savePassword = (event)=>{
            this.setState({password:event.target.value})
        }
        handleSubmit = (event)=>{
            // 阻止默认提交
            event.preventDefault()
            const {username,password} = this.state
            alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
        }
        render(){
            return (
                <form action="http://www.atguigu.com" onSubmit={this.handleSubmit}> 
                    用户名:<input type="text" name="username" onChange={this.saveUsername} />
                    密码:<input type="password" name="password" onChange={this.savePassword} />
                    <button>登录</button>
                </form>
            )
        }
      }
        // 渲染组件
        ReactDOM.render(<Login />, document.getElementById('test'))
    </script>

(2)非受控组件

 <script type="text/babel">
      class Login extends React.Component{
        handleSubmit = (event)=>{
            // 阻止默认提交
            event.preventDefault()
            const {username,password} = this
            alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
        }
        render(){
            return (
                <form action="http://www.atguigu.com" onSubmit={this.handleSubmit}> 
                    用户名:<input type="text" name="username" ref={c =>this.username=c} />
                    密码:<input type="password" name="password" ref={c =>this.password=c} />
                    <button>登录</button>
                </form>
            )
        }
      }
        // 渲染组件
        ReactDOM.render(<Login />, document.getElementById('test'))
    </script>

4.组件生命周期

(1)旧生命周期

 生命周期的三个阶段(旧)

初始化阶段: ReactDOM.render()触发---初次渲染

  1. constructor()
  2. componentWillMount()
  3. render()
  4. componentDidMount()

更新阶段: 由组件内部this.setSate()或父组件重新render触发

  1. shouldComponentUpdate()

  2. componentWillUpdate()

  3. render()

  4. componentDidUpdate()

卸载组件: ReactDOM.unmountComponentAtNode()触发

        componentWillUnmount()

(2)新生命周期

 生命周期的三个阶段(新)

初始化阶段: ReactDOM.render()触发---初次渲染

  1. constructor()

  2. getDerivedStateFromProps

  3. render()

  4. componentDidMount()

更新阶段: 由组件内部this.setSate()或父组件重新render触发

  1. getDerivedStateFromProps

  2. shouldComponentUpdate()

  3. render()

  4. getSnapshotBeforeUpdate

  5. componentDidUpdate()

卸载组件: ReactDOM.unmountComponentAtNode()触发

        componentWillUnmount()

(3)重要钩子

  1. render:初始化渲染或更新渲染调用

  2. componentDidMount:开启监听, 发送ajax请求

  3. componentWillUnmount:做一些收尾工作, : 清理定时器

(4)即将废弃的勾子

  1. componentWillMount

  2. componentWillReceiveProps

  3. componentWillUpdate

现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。

新增钩子getDerivedStateFromProps的使用场景:使用罕见,若state的值在任何时候都取决于props,那么可以使用。

新增钩子getSnapshotBeforeUpdate的使用场景:

 <script type="text/babel">
        class NewsList extends React.Component {
            state = {
                newsArr: []
            }
            componentDidMount() {
                setInterval(() => {
                    const { newsArr } = this.state
                    // 模拟新闻
                    const news = '新闻' + (newsArr.length + 1)
                    // 更新状态
                    this.setState({ newsArr: [news, ...newsArr] })
                }, 1000);
            }
            getSnapshotBeforeUpdate() {
                return this.refs.list.scrollHeight
            }
            componentDidUpdate(preProps, preState, height) {
                this.refs.list.scrollTop += this.refs.list.scrollHeight - height
            }
            render() {
                return (
                    <div className="list" ref="list">
                        {
                            this.state.newsArr.map((n, index) => {
                                return <div className="news" key={index}>{n}</div>
                            })
                        }
                    </div>
                )
            }
        }
        ReactDOM.render(<NewsList />, document.querySelector('#test'))
    </script>

四、高阶函数和函数柯里化

1.高阶函数

如果一个函数符合下面两个规范的任何一个,那该函数就是高阶函数:

  1. 若a函数,接收的参数是一个函数,那么a函数就可以称之为高阶函数。

  2. 若a函数,调用的返回值依然是一个函数,那么a就可以称之为高阶函数。

案例:

<script type="text/babel">
        class Login extends React.Component {
            state = {
                username: '',
                password: ''
            }
            saveFormData = (dataType) => event => this.setState({ [dataType]: event.target.value })
            handleSubmit = (event) => {
                // 阻止默认提交
                event.preventDefault()
                const { username, password } = this.state
                alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
            }
            render() {
                return (
                    <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
                        {/* onChange={this.saveFormData('username')}意思是将this.saveFormData('username')函数的返回值交给了onChange */}
                        用户名:<input type="text" name="username" onChange={this.saveFormData('username')} />
                        密码:<input type="password" name="password" onChange={this.saveFormData('password')} />
                        <button>登录</button>
                    </form>
                )
            }
        }
        // 渲染组件
        ReactDOM.render(<Login />, document.getElementById('test'))
    </script>

2.函数柯里化

通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

简例:求和案例

 function sum(a) {
            return (b) => {
                return c => {
                    return a + b + c
                }
            }
        }
 const result = sum(1)(2)(3)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值