'假的'必学必会之 React基础

453 阅读6分钟

1. React是什么?

  • react是一个用于构建用户界面的JS库,核心是专注于视图,目的是组件化开发

2. 组件化开发

  • 组件化概念:

    • 可组合:一个组件可以喝其他组件一起结合使用,可拆可组合,就好像乐高积木一样。

    • 可重用:每个组件都是具有独立功能的,可以被使用在多个场景中。

    • 可维护:每个小的组件仅仅包含自身逻辑,更容易被理解和维护

3. 搭建开发环境

npm i create-react-app -g // 全局安装react的官方脚手架
执行create-react-app 项目名称 // 执行脚手架命令创建项目
cd 项目名称  // 切换到想缪目录中区
yarn start  启动项目
  • React会自动安装,且分为两部分:

    • react.js 是React的核心库
    • react-dom.js是关于DOM操作相关的功能,render方法是其中重要方法,用来西安浏览器里插入DOM元素。

4. JSX语法

  • 什么是JSX

    • jsx是一种将JS和XML混合编写的语法,是将数据和组件结构聚合在一起定义组件。该语法在浏览器无法识别需要babel.js转译为createElement语法才行。
    ReactDOM.render(<h1>hello world</h1>, document.getElementById('root'));
    
  • 什么是元素

    • 元素是构成R额熬出头应用的最小单位
    • 他也是用来描述你在屏幕上看到的内容
    • react中的元素事实上是普通的JS对象,ReactDOM来确保浏览器中的DOM数据和React元素保持一致性
    <h1 className="title" style={{color: 'red'}}>hello</h1>
    
    • 转化为react元素就是这样表示的
    React.createElement('h1', {
        className: "title",
        style: {
            color: 'red'
        }
    }, "hello");
    
    • 编译后的结果是这样的:
    {
        type: 'h1',
        props:{
            className: 'title',
            style: {
                color: 'red'
            }
        },
        children: "hello"
    }
    
  • JSX属性

      1. jsx并不是HTML,所以其中不可以包含关键字,比如:class需要写成“className”, for需要写成“htmlFor”,而且属性名必须写成驼峰命名法,变量要写在大括号内。
      1. 在jsx中可以使用iffor语句
      1. 可以把jsx赋值给变量,当作参数传入,也可以当做返回值

    if和变量的使用:

    import React from 'react';
    import ReactDOM from 'react-dom';
    function greeting(name) {
        if(name) {
            return <h1>Hello, {name}</h1>;
        }
        return <h1>Hello, Stranger</h1>;
    }
    let name = 'World';
    const element = greeting(name);
    ReactDOM.render(elemnet, document.getElementById('root'));
    

    for的使用:

    import React from 'react';
    import ReactDOM from 'react-dom';
    let names = ['anna', 'lily', 'tom'];
    let eles = [];
    for (let i=0; i < name.length; i++) {
    <!--此处的key是为domdiff策略做铺垫-->
        eles.push(<li key ={name[i]}>name[i]</li>)
    }
    ReactDOM.render(
        <ul>
            {eles}
        </ul>
        document.getElementById('root')
    );
    
  • 更新元素

    • react元素都是immutable不可变的,当元素被创建之后,你是无法改变其内容或者属性的。一个元素就好像动画里面的一帧,他代表的是应用界面在某一个时刻的样子
    • 更新界面的唯一方法传建一个新的元素,然后将它传入ReactDOM.render()方法
    • 而且,很重要的一点就是ReactDOM只会更新必要的部分(性能优化的结果),他们会先去比对新老元素,然后决定更新的部分。即便是你创建了一整颗UI树也是如此。
import React from 'react';
import ReactDOM from 'react-dom';
function tick() {
    const element = (
      <div>
        {new Date().toLocaleTimeString()}
      </div>
    );
    ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);

5、组件&Props

  • 组件划分:

    • 函数组件:函数组件接受一个单一的props对象并返回一个React元素
    function Welcome(props) {
        return <h1>Hello, {props.name}</h1>
    }
    
    • 类组件:ES6class声明的组件
    class Welcome extends           React.Component {
        render(){
          return <h1>Hello, {this.props.name}</h1>
        }
    }
    
  • 组件的渲染

    • React元素不但可以是DOM标签,还可以是用户自定义的组件
    • 当 React元素为用户自定义组件时,它会将 JSX所接收的属性(attributes)转换为单个对象传递给组件,这个对象被称之为 props
    • 组件名称必须以大写字母开头组件必须在使用的时候定义或引用它组件的返回值只能有一个根元素。
    • 组件的复合和拆分:组件由于嵌套变得难以被修改,可复用的部分也难以被复用,所以可以把大组件切分为更小的组件。当然我们也不能把组件拆分的过于小反而会让代码组件不好管理。
    class Panel extends Component{
        render(){
    //解构出必要的变量,用到DOM结构上
        let {header,body} = this.props;
            return (
                <div className="container">
                    <div       className="panel-default panel">
                    <Header header={header}></Header>
                    <Body body={body}/>
                    </div>
                 </div>
            )
        }
    }
    
    class Body extends Component{
        render(){return (<div className="panel-body">{this.props.body}</div>)}
    }
    class Header extends Component {
      render(){
        return (<div className="panel-heading">{this.props.header}</div>
      }
    }
    let data ={header:'head',body:'body'};
    ReactDOM.render(
    <Panel {...data}/>,window.root);
    
  • Props的只读与类型检查

    • 无论是使用函数或是类来声明一个组件,它决不能修改它自己的props
    • 纯函数没有改变它自己的输入值,当传入的值相同时,总是会返回相同的结果
    • 所有的React组件必须像纯函数那样使用它们的props
    • 要在组件的props上进行类型检查,你只需配置特定的 propTypes 属性
    • 可以通过配置特定的defaultProps属性来定义props的默认值
    import PropTypes from 'prop-types';
    MyProps.propType = {
    // 你可以将属性声明为 JS 原生类型,默认情况下
    // 这些属性都是可选的
        optionalArray: PropTypes.array,
        optionalBool: PropTypes.bool,
        optionalFunc: PropTypes.func,
        optionalNumber: PropTypes.number,
        optionalObject: PropTypes.object,
        optionalString: PropTypes.string,
        optionalSymbol: PropTypes。symbol,
        // 任何可被渲染的元素(包括数字、字符串、元素或数组)
        // (或 Fragment) 也包含这些类型。
        optionalNode: PropTypes.node,
    
        // 一个 React 元素。
        optionalElement: PropTypes.element,
    
        // 你也可以声明 prop 为类的实例,这里使用
        // JS 的 instanceof 操作符。
        optionalMessage: PropTypes.instanceOf(Message),
    
        // 你可以让你的 prop 只能是特定的值,指定它为
        // 枚举类型。
        optionalEnum: PropTypes.oneOf(['News', 'Photos']),
    
         // 一个对象可以是几种类型中的任意一个类型
        optionalUnion: PropTypes.oneOfType([
            PropTypes.string,
            PropTypes.number,
             PropTypes.instanceOf(Message)
        ]),
    
        // 可以指定一个数组由某一类型的元素组成
        optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
    
        // 可以指定一个对象由某一类型的值组成
        optionalObjectOf: PropTypes.objectOf(PropTypes.number),
    
        // 可以指定一个对象由特定的类型值组成
        optionalObjectWithShape: PropTypes.shape({
            color: PropTypes.string,
            fontSize: PropTypes.number
        }),
    
        // 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
        // 这个 prop 没有被提供时,会打印警告信息。
        requiredFunc: PropTypes.func.isRequired,
    
        // 任意类型的数据
        requiredAny: PropTypes.any.isRequired,
        
        // 你可以指定一个自定义校验器,他会在校验失败时返回一个Error对象
        // 请不要使用'console.warn'或抛出异常,因为这在```onOf```中不会被检测到
        customProp: function(prop, propName, componentName) {
            if(!/regexp/.test(props[propName])) {
                return new Error(
                `invaild prop${propName}supplied to${componentName},Validation failed`)
            };
        }
    },
    customArrayProp: PropType.arrayOf(function(propValue, key, componentName, location, propFullName) {
        if(!/regexp/.test(propValue[key])) {
            return new Error(
            `invaild prop${propFullName}supplied to${componentName}Validation failed.` 
            )
        }
    }
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import PropTypes from 'prop-types';
    class Person extends React.Component{
    static defaultProps = {
        name:'Stranger'
    }
    static propTypes={
        name: PropTypes.string.isRequired,
        age: PropTypes.number.isRequired,
        gender: PropTypes.oneOf(['male','famale']),
        hobby: PropTypes.array,
        postion: PropTypes.shape({
            x: PropTypes.number,
            y:PropTypes.number
        }),
        age(props,propName,componentName) {
            let age=props[propName];
            if (age <0 || age>120) {
                return new Error(`Invalid Prop ${propName} supplied to ${componentName}`)
            }
        }
     }
    render() {
        let {name,age,gender,hobby,position}=this.props;
        return (
            <table>
                <thead>
                <tr>
                    <td>姓名</td>
                    <td>年龄</td>
                    <td>性别</td>
                    <td>爱好</td>
                    <td>位置</td>
                </tr>
                </thead>
                <tbody>
                <tr>
                    <td>{name}</td>
                    <td>{age}</td>
                    <td>{gender}</td>
                    <td>{hobby.join(',')}</td>
                    <td>{position.x+' '+position.y}</td>
                </tr>
                </tbody>
            </table>
        )}
    }
    let person={
    age: 100,
    gender:'male',
    hobby: ['basketball','football'],
    position: {x: 10,y: 10},
    }
    ReactDOM.render(<Person {...person}/>, document.getElementById('root'));