React组件基础

发布时间:2022-06-28 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了React组件基础脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

目录

    • 1. 模块化和组件化的区别
    • 2. react组件介绍
    • 3. react组件的两种创建方式
      • 3.1 函数组件
      • 3.2 使用类创建组件
      • 3.3 用户定义的组件必须以大写字母开头
    • 4. 抽离组件为独立的JS文件
    • 5. react事件处理
      • 5.1 事件绑定
        • 类组件中的事件绑定
        • 函数组件中的事件绑定
      • 5.2 事件对象
    • 6. 有状态组件和无状态组件
    • 7. React.PureComponent
    • 8. 组件的state和setState
      • 8.1 state
      • 8.2 setState()修改状态
    • 9. 事件绑定时this的指向
      • 9.1 箭头函数
      • 9.2 Function.prototype.bind()
      • 9.3 箭头函数形式的class实例方法
    • 10. 表单处理
      • 10.1 受控组件
      • 10.2 常见受控组件
      • 10.3 非受控组件
      • 10.4 小练习

1. 模块化和组件化的区别

  • 模块:向外提供特定功能的js程序, 一般就是一个js文件,达到复用代码的目的。当应用的js都以模块来编写的, 这个应用就是一个模块化的应用。
  • 组件:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等),组件是一个资源的集合,不仅仅包括js文件。当应用是以多组件的方式实现, 这个应用就是一个组件化的应用。

2. react组件介绍

JSX语法中的标签如果以小写字母开头,会被react默认按照html标签来解析,如果html中没有该标签对应的同名元素则报错。

如果以大写字母开头,react就会去渲染对应的组件,如果组件没有定义,则报错。

组件是react的一等公民,使用react就是在使用组件,组件表示页面的部分功能,组合多个组件实现完整页面功能。

3. react组件的两种创建方式

3.1 函数组件

使用JS的函数(或箭头函数)创建的组件叫做函数组件。

  • 函数名称必须以大写字母开头。react以此来区分组件和普通的react元素。使用函数名作为组件标签名
  • 函数组件必须有返回值,表示该组件的结构
  • 如果返回值是null,表示不渲染任何内容
// 函数组件
function Hello() {
  console.log(this) // undefined
  return (
    <h1>hello</h1>
  )
}

// 渲染
// ReactDOM.render(<Hello />, document.getElementById('root'))

// 使用单标签和双标签都可以
ReactDOM.render(<Hello></Hello>, document.getElementById('root'))
// 使用箭头函数创建组件
const Hello = () => <div>函数组件哦</div>;

如果直接打印this,结果是undefined。原因:在严格模式下,

  • 禁止this指向全局对象
  • 顶层的this指向undefined

babel在转换jsx语法时,会启用严格模式,从图中可以看书jsx语法是React.createElement的语法糖

React组件基础

当执行ReactDOM.render(<Hello></Hello>, document.getElementById('root'))时发生了什么?

  1. react解析组件标签,找到对应的组件
  2. 发现组件是函数组件,则调用该函数,将返回的虚拟DOM转为真实DOM,然后渲染到页面上

3.2 使用类创建组件

使用ES6的class创建的组件叫做类组件。

  • 类名必须以大写字母开头
  • 类组件应该继承React.Component父类,从而可以使用父类中的属性和方法
  • 类组件必须提供render()方法
  • render()方法必须有返回值,表示组件的结构。如果不想渲染任何内容,也要返回null
// 类组件
class Hello extends React.Component {
  render() {
    return (
      <div>这是类组件</div>
    )
  }
}

// 渲染
ReactDOM.render(<Hello/>, document.getElementById('root'))
  1. React解析组件标签,找到了 Component组件。
  2. 发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的 render方法,所以render方法中的this指向类的实例。
  3. 将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
  4. 如果在类中定义了方法,这些方法是定义在类的原型上的

3.3 用户定义的组件必须以大写字母开头

以小写字母开头的元素代表一个 HTML 内置组件,比如

或者 会生成相应的字符串 ‘div’ 或者 ‘span’ 传递给 React.createElement(作为参数)。大写字母开头的元素则对应着在 JavaScript 引入或自定义的组件,如 会编译为 React.createElement(Foo)。 ​ 如果你确实需要一个以小写字母开头的组件,则在 JSX 中使用它之前,必须将它赋值给一个大写字母开头的变量。 ​

4. 抽离组件为独立的JS文件

  1. 创建组件的js文件,如Hello.js
  2. 在Hello.js文件中导入React
  3. 创建组件(函数组件或类组件)
  4. 导出组件
  5. 在index.js中导入组件
  6. 渲染组件

创建Hello.js组件文件

import React from 'react';

class Hello extends React.Component {
    render() {
        return (
            <h1>我是组件的标题</h1>
        )
    }
}

// 导出组件
export default Hello

在index.js文件中导入组件

import React from 'react';
import ReactDOM from 'react-dom';

// 导入组件
import Hello from './components/Hello'

// 渲染
ReactDOM.render(<Hello/>, document.getElementById('root'))

5. react事件处理

5.1 事件绑定

react事件绑定语法与DOM事件语法类似。 (1)通过 onXxx属性指定事件处理函数(注意大小写)。React使用的是自定义(合成)事件。而不是使用的原生DOM事件,目的是为了更好的兼容性 (2)React中的事件是通过事件委托方式处理的(委托给组件最外层的元素),目的是为了高效 (3)通过event.target得到发生事件的dom元素对象 ​

语法:on + 事件名称 = {事件处理程序},如onClick = {() => {}},react事件采用驼峰命名法,如onMouseEnter ​

类组件中的事件绑定

class App extends React.Component {
    handleClick() {
        console.log('单击事件触发了');
    }

    render() {
        return (
            <button onClick={this.handleClick}>点击按钮</button>
        )
    }
}

// 渲染
ReactDOM.render(<App/>, document.getElementById('root'))

函数组件中的事件绑定

function App2() {

    function handleClick() {
        console.log('单击');
    }

    return (
        <button onClick={handleClick}>按钮</button>
    )
}

// 渲染
ReactDOM.render(<App2 />, document.getElementById('root'))

5.2 事件对象

  • 可以通过事件处理程序的参数获取到事件对象
  • react中的事件对象叫做:合成事件(对象)
  • 合成事件:兼容所有的浏览器,无须担心跨浏览器兼容性问题
class App extends React.Component {
    handleClick(e) {
      	// 阻止事件的默认行为
        e.preventDefault();
        console.log('单击事件触发了');
    }

    render() {
        return (
            <a href='https://www.baidu.com' onClick={this.handleClick}>百度</a>
        )
    }
}

// 渲染
ReactDOM.render(<App />, document.getElementById('root'))

6. 有状态组件和无状态组件

  • 函数组件又叫做无状态组件,函数组件没有自己的状态,只负责数据的静态展示
  • 类组件又叫做有状态组件,类组件有自己的状态,负责更新UI,让页面动起来
  • **状态(state)**就是数据

    React组件基础

7. React.PureComponent

React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而** React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。** ​ 如果赋予 React 组件相同的 props 和 state,render() 函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent 可提高性能。 ​ 注意 React.PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层比较。如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的比对结果。仅在你的 props 和 state 较为简单时,才使用 React.PureComponent,或者在深层数据结构发生变化时调用 forceUpdate() 来确保组件被正确地更新。 ​

此外,React.PureComponent 中的 shouldComponentUpdate() 将跳过所有子组件树的 prop 更新。因此,请确保所有子组件也都是“纯”的组件。 ​

8. 组件的state和setState

8.1 state

  • 状态state就是数据,是组件内部的私有数据,只能在组件内部使用
  • state的值是对象,表示一个组件中可以有多少数据
  • 通过this.state来获取状态
class App extends React.Component {
    constructor() {
        super();
        // 初始化state
        this.state = {
            count: 0
        }
    }

    render() {
        return (
            <div>计数器:{this.state.count}</div>
        )
    }
}

class App2 extends React.Component {
    // 简化语法初始化state
    state = {
        count: 0
    }

    render() {
        return (
            <div>计数器:{this.state.count}</div>
        )
    }
}

// 渲染
ReactDOM.render(<App2 />, document.getElementById('root'))

8.2 setState()修改状态

  • 状态是可变的
  • 语法:this.setState({要修改的数据})
  • 注意不要直接通过this.state.xxx = yyy修改state中的数据,这是错误的写法
  • setState的作用:1. 修改state 2. 更新UI
  • 当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state。这里的合并是浅合并。
class App2 extends React.Component {
    // 简化语法初始化state
    state = {
        count: 0
    }

    add() {
        console.log(this); // undefined
        this.setState({
            count: this.state.count + 1
        })
    }

    render() {
        return (
            <div>
                <h1>计数器:{this.state.count}</h1>
            
                {/* 如果直接这样写会报错, add方法内的this指向是undefined*/}
                {/* <button onClick={this.add}>+1</button> */}
            
                <button onClick={() => {
                    this.setState({
                        count: this.state.count + 1
                    })
                }}>+1</button>
            </div>
        )
    }
}

9. 事件绑定时this的指向

类中的方法默认开启了严格模式,this的指向可能为undefined。如果要让this重新指向当前组件实例,可以使用下边三种方法: ​

9.1 箭头函数

如果类的方式是通过实例调用的,那么方法中的this就指向当前实例。在绑定监听函数时,如果是这样写<button onClick={this.add}>+1</button>,相当于是将add方法作为点击事件的回调函数。当点击时,是直接取出这个函数执行,并不是通过实例调用的,所以此时this指向是undefined。

class App extends React.Component {
    state = {
        count: 0
    }

    add() {
        this.setState({
            count: this.state.count + 1
        })
    }

    render() {
        return (
            <div>
                <h1>计数器:{this.state.count}</h1>

                <button onClick={() => this.add()}></button>
            </div>
        )
    }
}

9.2 Function.prototype.bind()

将事件处理程序中的this绑定到当前组件实例。

class App extends React.Component {
    constructor() {
        super();
        this.state = {
            count: 0
        }
        // 在constructor中给事件处理方法绑定this,constructor中的this指向当前组件实例
        // add方法一开始在类的原型上,下边这个操作相当于给组件实例也添加了一个add方法,
        // 当调用add方法的时候,组件实例上的add会覆盖掉类原型上的
        this.add = this.add.bind(this);
    }

    add() {
        this.setState({
            count: this.state.count + 1
        })
    }

    render() {
        return (
            <div>
                <h1>计数器:{this.state.count}</h1>

                {/* 这里的onClick就可以正常调用add方法 */}
                <button onClick={this.add}>+1</button>
            </div>
        )
    }
}

9.3 箭头函数形式的class实例方法

实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层。当使用直接给一个变量赋值的形式时,该变量是直接定义在组件实例上的。下方代码中给add赋值了一个箭头函数,则add是直接定义在组件实例上,没有在原型上。

  • 利用箭头函数形式的class实例方法
  • 注意:该语法是实验性语法,但是由于babel的存在可以直接使用
class App extends React.Component {
    constructor() {
        super();
        this.state = {
            count: 0
        }
    }

    add = () => {
        this.setState({
            count: this.state.count + 1
        })
    }

    render() {
        return (
            <div>
                <h1>计数器:{this.state.count}</h1>

                {/* 这里的onClick可以正常调用add方法 */}
                <button onClick={this.add}>+1</button>
            </div>
        )
    }
}

10. 表单处理

在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。 ​

10.1 受控组件

  • 受控组件:其值受到react控制的表单元素
  • HTML中的元素是可输入的,也就是有自己的状态。而react中可变状态通常保存在state中,并且只能通过setState()方法来修改
  • react将state与表单元素值value绑定到一起,由state的值来控制表单元素的值

    React组件基础

处理步骤:

  1. 在state中添加一个状态,作为表单元素的value值(控制表单元素值的来源)
  2. 给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素值的变化)

这种操作类似于vue中的双向数据绑定

class App extends React.Component {
    state = {
        text: 'hello'
    }

    onInputChange = e => {
        console.log(e);
        this.setState({
            text: e.target.value
        })
    }

    render() {
        return (
            <input type="text" value={this.state.text} onChange={this.onInputChange} />
        )
    }
}

10.2 常见受控组件

class App extends React.Component {
    state = {
        text: 'hello',
        content: '富文本',
        city: 'bj',
        isChecked: false
    }

    onInputChange = e => {
        console.log(e);
        this.setState({
            text: e.target.value
        })
    }

    onTextareaChange = e => {
        this.setState({
            content: e.target.value
        })
    }

    onSelectChange = e => {
        this.setState({
            city: e.target.value
        })
    } 

    onCheckChange = e => {
        console.log(e.target.checked);
        this.setState({
            isChecked: e.target.checked
        })
    }

    render() {
        return (
            <div>
                {/* 文本框 */}
                <input type="text" value={this.state.text} onChange={this.onInputChange} />

                {/* 富文本框 */}
                <textarea value={this.state.content} onChange={this.onTextareaChange}></textarea>

                {/* 下拉框 */}
                <select value={this.state.city} onChange={this.onSelectChange}>
                    <option value="sh">上海</option>
                    <option value="zz">郑州</option>
                    <option value="bj">北京</option>
                </select>

                {/* 复选框,有defaultChecked属性,它只在初次渲染的时候起作用 */}
                <input type="checkbox" checked={this.state.isChecked} onChange={this.onCheckChange} />
            </div>

        )
    }
}

上边的代码中对于每一个表单控件都有一个事件处理程序,对上述代码进行优化,让所有的表单控件共用一个事件处理程序。

  1. 给表单控件添加name属性,名称与state相同
  2. 根据表单元素类型获取对应的值
  3. 在change事件处理程序中通过[name]来修改对应的state

    React组件基础

10.3 非受控组件

  • 借助于ref,使用原生DOM方式来获取表单元素
  • ref的作用,获取DOM或组件

使用步骤:

  1. 调用React.createRef()方法创建一个ref对象
  2. 将创建好的ref对象添加到文本框中
  3. 通过ref对象获取到文本框的值
import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
    constructor() {
        super();
        this.textRef = React.createRef();
    }

    getText = e => {
        console.log(this.textRef.current.value);
    }

    render() {
        return (
            <div>
                <input type="text" ref={this.textRef} />
                <button onClick={this.getText}>获取文本框的值</button>
            </div>
        )
    }
}

// 渲染
ReactDOM.render(<App />, document.getElementById('root'))

10.4 小练习

实现发表评论的组件

React组件基础

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
    state = {
        comments: [
            { id: 1, name: 'jack', content: '看看' },
            { id: 2, name: 'xiaoming', content: '看看3' },
            { id: 3, name: '打断点', content: '看看5' }
        ],
        username: '',
        commentContent: ''
    }

    renderList() {
        // 研究一下这里this的指向问题
        console.log(this);
        let { comments } = this.state;
        if (comments.length === 0) {
            return (<div>暂无评论</div>)
        }

        return (
            <ul>
                {comments.map(item => {
                    return (
                        <li key={item.id}>
                            <h3>评论人:{item.name}</h3>
                            <p>评论内容:{item.content}</p>
                        </li>
                    )
                })}
            </ul>
        )
    }

    handleForm = e => {
        let { name, value } = e.target;
        this.setState({
            [name]: value
        })
    }

    pubComment = () => {
        let { comments, username, commentContent } = this.state;
        if(!username.trim() || !commentContent.trim()) {
            return alert('内容不能为空')
        }
        let comment = {
            id: comments.length + 1,
            name: username,
            content: commentContent
        }
        comments.unshift(comment)
        this.setState({
            comments,
            commentContent: '',
            username: ''
        })
    }

    render() {
        return (
            <div>
                <div>
                    <input type="text" name="username" value={this.state.username} placeholder="评论人" onChange={this.handleForm} />
                    

                    <textarea name="commentContent" value={this.state.commentContent} cols="30" rows="10" placeholder="评论内容" onChange={this.handleForm}></textarea>
                    

                    <button onClick={this.pubComment}>发表评论</button>
                </div>
                {
                    this.renderList()
                }
            </div>
        )
    }
}

// 渲染
ReactDOM.render(<App />, document.getElementById('root'))

前端学习交流QQ群:862748629

脚本宝典总结

以上是脚本宝典为你收集整理的React组件基础全部内容,希望文章能够帮你解决React组件基础所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: