2021-05-23

本文详细介绍了React的基本概念,包括声明式设计、虚拟DOM和Diff算法。通过实例展示了如何创建React组件,理解JSX、props、state以及事件处理。文中还探讨了组件状态管理和条件与循环渲染,以及表单的受控和非受控组件的使用。
摘要由CSDN通过智能技术生成

React入门教程

什么是 React 

React 是一个用于构建用户界面的 JavaScript 库。它主要用于构建 UI,相当于 MVC 中的 V(视图)。

React 特点

1. 声明式设计:React 采用声明范式,可以轻松描述应用。
2. 高效性:React 通过对 DOM 的模拟,最大限度地减少与 DOM 的交互。
3. 灵活性:React 能与已知的库或框架很好地配合使用。
4. JSX JSX 是 JavaScript 语法的扩展。
5. 组件:通过 React 构建组件,使得代码更加容易得到复用。
6. 单向响应的数据流:React 实现了单向响应的数据流,从而减少了重复代码。

 其中单项数据流虚拟 DOM Diff 算法是 React 的核心特点。

1.单项数据流

  • state:驱动应用的数据源

  • view:以声明方式将 state 映射到视图

  • actions:响应在 view 上的用户输入导致的状态变化

 简单的单向数据是指用户访问 ViewView 发出用户交互的 Action,在 Action 里对 State 进行相应更新,State 更新后会触发 View 更新页面的过程。

2.虚拟 DOMVirtual DOM

传统的 Web 应用,操作 DOM 一般都是直接更新操作的,但是我们知道 DOM 更新通常是比较昂贵的,页面节点每发生一次变化,都会导致整个页面的重绘和回流。

React 为了尽可能减少对 DOM 的操作,提供了一种和传统 DOM 操作完全不同方式来更新 DOM,代替了传统 Web 应用中直接的 DOM 操作,这种全新的操作 DOM 的方式就是 Virtual DOM

3. Diff 算法

在虚拟 DOM 中,会用 JavaScript 对象结构表示一个虚拟 DOM 树的结构,然后再用这个虚拟 DOM 树构建一个真正的 DOM 树,插入到文档当中。

安装 React

1.使用 CDN 的方式来引入 React

<!-- 引入 React 核心库 -->
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>

2.使用 npm 命令

npm config set registry https://registry.npm.taobao.org

3.使用 create-react-app 快速构建 React 开发环境

npm install -g create-react-app

4.创建 React 项目,demo就是新创建的项目名称

React 元素

JSX

JSX 的创建

const ele = (<h1>this is a test</h1>);

JSX 的优点

  • JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。

  • 它是类型安全的,在编译过程中就能发现错误。

  • 使用 JSX 编写模板更加简单快速。

在 JSX中,根元素只能有一个,如果出现多个根元素,React 将不能正常渲染。

JSX 使用

1. JavaScript 表达式

JSX 中不能使用 if else 语句,但可以使用 conditional(三元运算)表达式来替代。

<body>
    <div id="app"></div>
    <script type="text/babel">
        const age = 18;
        const ele = (
            <div>
                <h1>{age >= 18 ? '你已经成年' : '你还未成年'}</h1>
            </div>
        );
        ReactDOM.render(ele , document.getElementById('app'));
    </script>
</body>

2. CSS样式设置

<body>
    <div id="app"></div>
    <script type="text/babel">
        const myStyle = {
            fontSize : 44,
            color : 'blue'
        };
        ReactDOM.render(
            <h1 style = {myStyle}>this is a test</h1>,
            document.getElementById('app')
        );
      </script>
</body>

3.类名设置 className

如果我们在 JSX 中要给标签设置 class,不能够像 HTML 中那样直接书写 class。在 JavaScript 中拥有 class 关键字,表示类。所以 class 需要替换为 className

<body>
    <div id="app"></div>
    <script type="text/babel">
        ReactDOM.render(
            <h1 className="test">this is a test</h1>,
            document.getElementById('app')
        );
      </script>
</body>

4. 注释

{/* 注释内容... */}

5. 数组

<body>
    <div id="app"></div>
    <script type="text/babel">
        const arr = [
            <h1>欢迎来到 React</h1>,
            <h2>React 是当经最流行的前端框架!</h2>,
        ];
        const ele = (
            <div>
                { arr }
            </div>
        );
        ReactDOM.render(ele , document.getElementById('app'));
      </script>
</body>

React 组件

React 通过组件的思想,将应用界面拆分成一个个可复用的模块,每一个模块就是一个 React 组件。一个 React 应用由若干组件组合而成,一个组件由若干个 React 元素组合而成,一个复杂组件也可以由若干简单组件组合而成。

创建组件

1. 函数式组件

<body>
    <div id="app"></div>
    <script type="text/babel">
        // 这是函数式组件
        function HelloMessage() {
            return (
                <div>
                    <h1>欢迎学习 React</h1>
                    <ul>
                        <li>JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。</li>
                        <li>它是类型安全的,在编译过程中就能发现错误。</li>
                        <li>使用 JSX 编写模板更加简单快速。</li>
                    </ul>
                </div>
            );
        }
        ReactDOM.render(<HelloMessage />,document.getElementById('app'));
    </script>
</body>

2. 类定义组件

<body>
    <div id="app"></div>
    <script type="text/babel">
        // 这是类定义式组件
        class Welcome extends React.Component {
            render() {
                return (
                    <div>
                        <h1>欢迎学习 React</h1>
                        <ul>
                            <li>JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。</li>
                            <li>它是类型安全的,在编译过程中就能发现错误。</li>
                            <li>使用 JSX 编写模板更加简单快速。</li>
                        </ul>
                    </div>
                );
            }
        }
        ReactDOM.render(<HelloMessage />,document.getElementById('app'));
    </script>
</body>

组合组件

组件最大的好处,就是将一个 UI 切分成了一块一块可复用的部件,所以我们在构建 UI 的时候,应该尽量创建可复用的组件,然后通过复合组件来构成我们的页面。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class HelloReact extends React.Component {
            render() {
                return <h1>hello React</h1>
            }
        }
        class HelloJSX extends React.Component {
            render() {
                return <h1>hello JSX</h1>
            }
        }
        class Welcome extends React.Component {
            render() {
                return (
                    <div>
                    <HelloReact />
                    <HelloJSX />
                </div>
                )
            }
        }
        ReactDOM.render(<Welcome/>, document.getElementById("app"));
      </script>
</body>

在实际开发中,尽可能多的复用组件,将一个大型的部件拆解成许多单个的组件。

Fragment

React 15 版本以前,return 后面返回的 React 元素必须有一个根节点,否则会报错。为了满足这一原则我们经常就会创建一个没有任何实际意义的 div 来包裹一下。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            render() {
                return (
                    <div>
                        <h1>Hello HTML</h1>
                        <h1>Hello CSS</h1>
                    </div>
                )
            }
        }
        ReactDOM.render(<Welcome/>, document.getElementById("app"));
      </script>
</body>

React 16 中还提供了一个 Fragment,用来表示不可见的包裹元素。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            render() {
                return (
                    <React.Fragment>
                        <h1>Hello HTML</h1>
                        <h1>Hello CSS</h1>
                    </React.Fragment>
                )
            }
        }
        ReactDOM.render(<Welcome/>, document.getElementById("app"));
  </script>
</body>

props

props 基本介绍

React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)转换为单个对象传递给组件,这个对象被称之为“props”。

换句话说:props 是组件对外的接口,在组件内部,可以通过 props 拿到外部传给组件的参数。

<body>
    <div id="app"></div>
    <script type="text/babel">
        // props 为一个对象,接收传递过来的属性
        function HelloMessage(props) {
            return (
                <div>
                    <p>姓名:{props.name}</p>
                    <p>年龄:{props.age}</p>
                    <p>性别:{props.gender}</p>   
                </div>
            );
        }
        // 渲染组件时将属性传递到组件里面
        ReactDOM.render(<HelloMessage name = "zhangsan" age = {18} gender = "male"/>,document.getElementById('app'));
    </script>
</body>

defaultprops

如同给函数设置默认参数值一样,我们也可以给 React 组件设置默认的 defaultprops,用于当组件没有传递属性时使用。

<body>
    <div id="app1"></div>
    <div id="app2"></div>
    <script type="text/babel">
        // props 为一个对象,接收传递过来的属性
        function HelloMessage(props) {
            const { name,age,gender } = props;
            return (
                <div>
                    <p>姓名:{name}</p>
                    <p>年龄:{age}</p>
                    <p>性别:{gender}</p>   
                </div>
            );
        }
        // 设置默认的 props 值,当组件没有传值时会使用默认值
        HelloMessage.defaultProps = {
            name : 'zhangsan',
            age : 18,
            gender : 'male'
        };
        // 渲染组件时将属性传递到组件里面
        ReactDOM.render(<HelloMessage />,document.getElementById('app1'));
        ReactDOM.render(<HelloMessage name="yajing" age={20} gender="female"/>,document.getElementById('app2'));
    </script>
</body>

事件处理

为组件绑定事件

React 中绑定事件时需要采用驼峰命名法,并且对应的值为一个函数,而不是一个字符串。

<button onClick={activateLasers}>
    Activate Lasers
</button>

this 的指向问题的三种解决方式

1.将事件处理函数修改为箭头函数

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            eventHandler = () => {
                console.log(this); 
                // Welcome {props: {…}, context: {…}, refs: {…}, updater: {…}, eventHandler: ƒ, …}
            }
            render() {
                return (
                    <div onClick = {this.eventHandler}>this is a test</div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

2.使用 bind 方法来强制绑定 this 的指向

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            constructor(){
                super();
                this.eventHandler = this.eventHandler.bind(this); // 强制绑定 this 的指向
            }
            eventHandler(){
                console.log(this); 
                // Welcome {props: {…}, context: {…}, refs: {…}, updater: {…}, eventHandler: ƒ, …}
            }
            render() {
                return (
                    <div onClick = {this.eventHandler}>this is a test</div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

3.在绑定时候的时候,以箭头函数的形式进行绑定

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            eventHandler(){
                console.log(this);
            }
            render() {
                return (
                    <div onClick = {() => this.eventHandler()}>this is a test</div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

向事件处理程序传参

1.通过 bind 方法在绑定 this 指向时向事件处理函数进行传参。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            // 事件处理函数可以接收 2 个参数:额外参数、事件对象
            eventHandler = (str,e) => {
                console.log(str); // Hello
                console.log(e); // Proxy {dispatchConfig: {…}, _targetInst: FiberNode, nativeEvent: MouseEvent, type: "click", target: div, …}
                console.log(this); // Welcome {props: {…}, context: {…}, refs: {…}, updater: {…}, eventHandler: ƒ, …}
            }
            render() {
                return (
                    // 通过 bind 方法来传递参数,书写 2 个参数:绑定的 this 指向,额外参数
                    <div onClick = {this.eventHandler.bind(this,'Hello')}>this is a test</div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

2.通过绑定事件时,通过书写箭头函数的形式来传参。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            // 事件处理函数可以接收 2 个参数:额外参数、事件对象
            eventHandler = (str,e) => {
                console.log(str); // Hello
                console.log(e); // Proxy {dispatchConfig: {…}, _targetInst: FiberNode, nativeEvent: MouseEvent, type: "click", target: div, …}
                console.log(this); // Welcome {props: {…}, context: {…}, refs: {…}, updater: {…}, eventHandler: ƒ, …}
            }
            render() {
                return (
                    // 绑定事件时通过书写箭头函数的形式来传参
                    <div onClick = {(e)=>this.eventHandler('Hello',e)}>this is a test</div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

state

state 基本概念

在我们的组件中,自身所拥有的数据又被称之为状态。所以这一类组件往往被称之为有状态组件。在组件中我们可以通过 state 来定义组件的数据(状态),state 是一个对象。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            constructor(){
                super();
                // 设置组件自身的数据状态
                this.state = {
                    name : 'xiejie',
                    age : 18,
                    gender : 'male'
                }
            }
            render() {
                return (
                    <div>
                        <p>姓名:{this.state.name}</p>
                        <p>年龄:{this.state.age}</p>
                        <p>性别:{this.state.gender}</p>   
                    </div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

修改组件状态

state 的主要作用就是用于组件保存、控制以及修改自己的数据状态,它只能在 constructor 中初始化,算是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的 setState 方法来进行修改。

该方法是 React 提供的专门用于更新 state 的方法。state 一旦更新就会主动触发 render 方法。而每次 render 方法触发时,React 内部都有一个算法会自动对比更新后和更新前的差异,然后重新渲染数据发生变化的节点。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            constructor(){
                super();
                // 设置组件自身的数据状态
                this.state = {
                    num : 1
                }
            }
            eventHandler = () => {
                // 使用 this.setState 方法来设置组件自身的状态数据
                this.setState({
                    num: this.state.num + 1
                })
            }
            render() {
                return (
                    <div>
                        <p>当前值为:{this.state.num}</p>
                        <button onClick={this.eventHandler}>change state</button>
                    </div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

setState 执行完成后,去读取 state 中的数据,却发现数据未更新。这是因为为了提升性能,React 会把多次 setState 操作合并成一次,所以 setState 执行的过程是异步的。也就是说,setState 执行后并没有立刻更新 state 中的数据。

解决此问题的最好办法是把计算结果存储下来。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            constructor(){
                super();
                // 设置组件自身的数据状态
                this.state = {
                    num : 1
                }
            }
            eventHandler = () => {
                let newCount = this.state.num + 1; // 使用一个变量来计算结果存储下来
                this.setState({
                    num: newCount
                })
                console.log(newCount); // 期望是 2,实际也是 2
            }
            render() {
                return (
                    <div>
                        <p>当前值为:{this.state.num}</p>
                        <button onClick={this.eventHandler}>change state</button>
                    </div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

其实 React 也为我们提供了另一个方法,setState 还有第二个参数,它是一个函数,这个函数会在 state 更新后被调用。

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Welcome extends React.Component {
            constructor(){
                super();
                // 设置组件自身的数据状态
                this.state = {
                    num : 1
                }
            }
            eventHandler = () => {
                this.setState({
                    num: this.state.num + 1
                },()=>{
                    console.log(this.state.num); // 期望是 2,实际也是 2
                })
            }
            render() {
                return (
                    <div>
                        <p>当前值为:{this.state.num}</p>
                        <button onClick={this.eventHandler}>change state</button>
                    </div>
                );
            }
        }
        ReactDOM.render(<Welcome/>,document.getElementById('app'));
    </script>
</body>

props 和 state 的区别:

  • state 是组件自己管理数据,控制自己的状态,可变。

  • props 是外部传入的数据参数,不可变。

  • 使用函数创建的组件为无状态组件,使用类方式声明的组件为有状态组件。

  • 无状态组件(函数创建的组件)无法定义 state 状态。

  • 多用 props,少用 state。也就是多写无状态组件,这样更方便对数据的统一管理。

条件与循环

条件渲染

React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或者条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI

<body>
    <div id="app"></div>
    <script type="text/babel">
        function Com1() {
            return (
              <ul>
                <li>香蕉</li>
                <li>苹果</li>
              </ul>
            );
          }
          // 组件 2
          function Com2() {
            return (
              <ul>
                <li>电影</li>
                <li>音乐</li>
              </ul>
            );
          }
        class Com extends React.Component {
            state = {
                 whichCom : true
            // 修改 whichCom 状态值
            changeState(){
                this.setState({
                    whichCom : !this.state.whichCom
                });
            }
            render() {
                return (
                    // 为 button 绑定点击事件,更改 whichCom 的值,状态值一改变,页面就会重新渲染
                    <div>
                        <button onClick = {(e)=>this.changeState(e)}>切换</button>
                        {this.state.whichCom? <Com1/> : <Com2/>}
                    </div>
                );
            }
        }
        ReactDOM.render(<Com/>,document.getElementById('app'));
    </script>
</body>

有些时候,我们需要隐藏某些组件,这个时候设置该组件的 render 方法返回 null 即可。

列表渲染

所谓列表渲染,就是指循环渲染出某些内容

<body>
    <div id="app"></div>
    <script type="text/babel">
        class Content extends React.Component {
            data = ['苹果','香蕉','西瓜']; // 列表的数据
            render() {
                // 通过 map 方法进行映射
                let list = this.data.map((item)=>{
                    return (<li>{item}</li>);
                });
                return (
                    <ul>{list}</ul>
                );
            }
        }
        ReactDOM.render(<Content />,document.getElementById('app'));
    </script>
</body>

表单

React 中,表单的组件可以分为受控组件非受控组件

受控组件

用户在控件中所输入的内容都会在事件中进行限制。

<body>
    <div id="example"></div>
    <script type="text/babel">
        class Count extends React.Component {
            state = {
              value: "",
            };
            changeHandle = (e) => {
              this.setState({
                value: e.target.value,
              });
            };
            render() {
              return (
                <div>
                  <input type="text" name="" id="" value={this.state.value} onChange={this.changeHandle} />
                  <p>你输入的内容是:{this.state.value}</p>
                </div>
              );
            }
          }
          ReactDOM.render(<Count />, document.getElementById("app"));
    </script>
</body>

非受控组件

如果要让表单数据由 DOM 来进行处理时,替代方案为使用非受控组件。要编写一个非受控组件,而非为每个状态更新编写事件处理程序,可以使用 refDOM 获取表单值。

<body>
    <div id="app"></div>
    <script type="text/babel">
        // 在该表单组件中,没有通过组件的 state 值来关联控件内容
        // 所以该组件是一个非受控组件。在非受控组件中通过 ref 来获取控件的值
        class NameForm extends React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    value : ''
                };
                // 通过 React.createRef 方法来创建一个 ref
                this.refTest = React.createRef();
            }
​
            clickHandle = () => {
              this.setState({
                value: this.refTest.current.value,
              });
            };
            render() {
                return (
                    <div>
                      <input type="text" name="" id=""  ref={this.refTest} />
                      <p>你输入的内容是:{this.state.value}</p>
                      <button onClick={this.clickHandle}>click</button>
                    </div>
                );
            }
        }
        ReactDOM.render(<NameForm />,document.getElementById('app'));
    </script>
</body>

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值