美文网首页
Play With React

Play With React

作者: 梁某人的剑 | 来源:发表于2020-04-11 16:18 被阅读0次

    本文内容根据官方文档整理

    • 初始化项目
      • 查看本机npm版本
      • create-react-app脚手架初始化代码库
      • 执行,构建与测试
    • React基础知识
      • jsx语法
      • jsx中的元素
      • 组件
      • 组件state与LifeCycle
      • 单向数据流:组件的状态可以作为props传递给子组件(React实现组件化的基础,同时带来了组件间通信的问题)
      • React事件处理
      • 组件的条件渲染
      • 列表的Key值
      • 表单的使用——受控组件

    初始化项目

    查看本机npm版本

    npm -v
    6.4.1
    

    create-react-app脚手架初始化代码库

    • npm版本如果高于^5.2,需要使用npx命令
      • npx create-react-app play-with-react
        cd play-with-react
    • npm < 5.2,直接使用
      • create-react-app play-with-react
        cd play-with-react

    执行,构建与测试

    执行

    yarn start

    构建

    yarn build
    create react app默认的webpack配置会将src中的代码打包到项目根目录的build目录下,供部署使用。

    测试

    yarn test
    create react app已经为我们内置了Facebookjs单元测试框架Jest

    • 测试文件名约束

      1. 测试文件必须放在src目录下级目录中
      2. 测试文件可以是tests文件夹下的*.js文件
      3. 测试文件可以是任何目录下的.test.js文件或者.spec.js文件
    • 聚焦与排除

      1. 约定每个测试用例写在it()
      2. 使用fit()仅执行该测试用例
      3. 使用xit()排除该测试用例
    • 测试覆盖率

      1. npm test -- --coverage
      2. 可在package.json中进行配置覆盖率限制
      {
        "jest": {
          "collectCoverageFrom": [
            "src/**/*.{js,jsx}",
            "!<rootDir>/node_modules/"
          ],
          "coverageThreshold": {
            "global": {
              "branches": 90,
              "functions": 90,
              "lines": 90,
              "statements": 90
            }
          },
          "coverageReporters": ["text"]
        }
      }
      

    Reactj基础知识

    jsx语法

    jsx是js语言的扩展,使用它我们可以像下面这样在js代码中描述UI。

    const element = <h1>Hello World!</h1>
    

    jsx中可以嵌入js表达式

    const name = 'Liang Lingrui';
    const element = <h1>Hello, {name}</h1>;
    
    ReactDOM.render(
      element,
      document.getElementById('root')
    );
    

    jsx的大括号中可以包含任意合法的javascript表达式,包括函数执行表达式

    const formatName = (user) => (user.firstName + ' ' + user.lastName)
    
    const user = {
      firstName: 'Liang',
      lastName: 'Lingrui'
    };
    
    const element = (
      <h1>
        Hello, {formatName(user)}!
      </h1>
    );
    
    

    jsx编译之后本身也是表js达式

    const getGreeting = (user) => {
        const defaultElem = <h1>Hello, Stranger.</h1>
        const userElem = <h1>Hello, {formatName(user)}!</h1>
        if(user){
            return userElem
        }else{
            return defaultElem
        }
    }
    

    jsx中的元素

    元素的主要特点

    1. React应用中的最小组成单元
    2. 元素不是组件,是组件的组成部分
    3. 可以将组件定义为元素
    4. 元素描述了我们在屏幕上会看到什么,就是html标签
    5. 元素一旦创建,就不可变
    6. 只有创建一个新的element替换才可以改变UI
    7. React的diff机制会把新的element跟之前的element比较,仅替换所需的部分

    jsx中的element可以像html中一样使用属性,但是其属性名都采用驼峰命名规则

    const element = <div className="box"></div>;
    const element = <div tabIndex="0"></div>;
    const element = <img src={user.avatarUrl}></img>;
    
    

    jsx中的element可以有子元素

    const element = (
      <div>
        <h1>Hello!</h1>
        <h2>Good to see you here.</h2>
      </div>
    );
    

    jsx本身具备防注入攻击的特性,所有的用户输入默认在render之前都会被转为字符串,所以需要使用跨域功能时需要手动关闭这一特性

    jsx元素的本质

    const element = <h1 className="greeting">Hello, world!</h1>

    • 方便我们使用js语言表现UI的语法糖,实际调用了一个工厂方法去实例化一个js对象
    const element = React.createElement(
      'h1',
      {className: 'greeting'},
      'Hello, world!'
    );
    
    • 构造出来的对象数据结构:
    const element = {
      type: 'h1',
      props: {
        className: 'greeting',
        children: 'Hello, world!'
      }
    };
    

    组件

    组件的价值在于构造出独立可复用的UI单元,其具有自己的功能,同时维护自己的状态数据。

    组件的本质

    1. 在React中,组件就是函数,返回值为jsx中的emement
    2. 所有的组件必须是纯函数

    定义组件的两种方式

    1. 功能(函数式)组件:一个接受props作为参数的函数,返回值是jsx中的element
    const Welcome = (props) => (<h1>Hello, {props.name}</h1>)
    
    1. class式组件:继承于React中的Component类,render方法中返回element,ES6中的js语法糖,class的本质还是function
    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    

    组件可以定义为元素

    实际上是函数的调用,标签中的属性值都是props对象下的属性,都可以通过props访问到

    const element = <Welcome name="LLR" />;
    ---------------------------------------
    let props = {
        name : "LLR"
    }
    const element = Welcome(props)
    

    组件的聚合

    const Welcome = (props) => (<h1>Hello, {props.name}</h1>)
    
    const App = (props) => (
        <div>
          <Welcome name="Sara" />
          <Welcome name="Cahal" />
          <Welcome name="Edite" />
        </div>
    )
    

    props是不可修改,Read-Only

    因此,所有的函数式React组件都是纯函数。但是UI是交互式的、多变的,所以React引入了state来描述组件的表现状态。

    组件state与LifeCycle

    在class式的组件中才能使用state

    • 在class式的组件构造函数初始化state值
    class Clock extends React.Component{
        constructor(props) {
            super(props);
            this.state = {date: new Date()};
        }
        
        ...
    

    更新组件状态值可以自动触发生命周期函数

    Clock组件自己维护自己的状态信息

    class Clock extends React.Component{
        constructor(props) {
            super(props);
            this.state = {date: new Date()};
        }
        
        tick() {
            this.setState({
              date: new Date()
            });
        }
        
        componentDidMount() {
            this.timerID = setInterval(
                () => this.tick(),
                1000
              );
        }
    
        componentWillUnmount() {
            clearInterval(this.timerID);
        }
    
        render(){
            return (
                <div>
                    <h1>Hello, world!</h1>
                    <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
                </div>
            )
        }
    }
    

    不要直接修改state的值

    • 直接修改state的值可能不会触发组件的生命周期函数
    // Wrong
    this.state.comment = 'Hello';
    
    // Correct
    this.setState({comment: 'Hello'});
    

    React会将多个setState合并处理,props跟state可以异步更新,所以不要在setState的时候使用state/props来计算新的值

    // Wrong
    this.setState({
      counter: this.state.counter + this.props.increment,
    });
    

    setState方法是patch式的更新,会替换参数中的部分,state中原有的不会改变

    下面的代码在constructor中初始化了state对象包含posts跟comments两个属性,但是生命周期函数componentDidMount在调用的时候可以只更新posts属性。

    constructor(props) {
      super(props);
      this.state = {
        posts: [],
        comments: []
      };
    }
      
    componentDidMount() {
      fetchPosts().then(response => {
        this.setState({
          posts: response.posts
        });
      });
    }
    
    

    单向数据流:组件的状态可以作为props传递给子组件(React实现组件化的基础,同时带来了组件间通信的问题)

    如Clock案例中:

    <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
    

    也适用于自定义组件的属性值传递,FormattedDate组件并不知道date属性的值是来时用户输入还是父组件状态值

    const FormattedDate = (props) => (
      return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
    )
    <FormattedDate date={this.state.date} />
    

    React事件处理

    onClick属性方法可以handel元素/组件的点击事件,需要特别注意:将事件处理方法传递到子组件时要手动绑定this上下文,否则调用对象为undefined,这是js语法导致的问题,跟React无关

    class Switch extends React.Component {
      constructor(props) {
        super(props);
        this.state = {isToggleOn: true};
      }
    
      handleClick() {
        this.setState(state => ({
          isToggleOn: !state.isToggleOn
        }));
      }
    
      render() {
        return (
        // 调用bind方法绑定时间到this指向的对象
          <button onClick={this.handleClick.bind(this)}>
            {this.state.isToggleOn ? 'ON' : 'OFF'}
          </button>
        );
      }
    }
    

    使用ES6箭头函数可以避免这种绑定this的写法

    class Switch extends React.Component {
      
     handleClick() {
        console.log('haha')
      }
      
      render() {
        return (
        //  使用箭头函数做事件处理
          <button onClick={(e) => this.handleClick(e)}>
            {this.state.isToggleOn ? 'ON' : 'OFF'}
          </button>
        );
      }
    }
    

    组件的条件渲染

    js尽量考虑函数式编程

    • 用 && 号实现 if 的效果
      • 见代码中mailBox组件
    • 使用三目运算符,来实现行内的 if else 效果
      • 见代码中LoginControl组件

    列表的Key值

    React的list中每一个列表的条目都应该有一个Key来做唯一表示,通常是不可变的id属性。如果缺少Key浏览器会报错。引入Key的原理请查看深入理解React相关描述

    表单的使用——受控组件

    1. 为表单空间初始化state值,比如username
    2. 定义 handleChange 处理函数,里面修改 username 值
    3. render中,添加一个input使value值等于this.state.username
    4. 这个input就是一个受控组件,监听onChange事件更新用户输入保证输入数据的实时更新
    class Form extends React {
      state = { username: '', email: '' }
    
      handleChange = event => {
        const { value, name } = event.target
    
        this.setState({
          [name]: value
        })
      }
    
      handleSubmit = e => {
        console.log(`${this.state.username} ${this.state.email}`)
        e.preventDefault()
      }
    
      render() {
        return (
          <div>
            Username:
            <input
              name="username"
              type="text"
              value={this.state.username}
              onChange={this.handleChange}
            />
            <br />
            Email:
            <input
              name="email"
              type="text"
              value={this.state.email}
              onChange={this.handleChange}
            />
            <br />
            <button onClick={this.handleSubmit}>提交</button>
          </div>
        )
      }
    }
    
    
    

    相关文章

      网友评论

          本文标题:Play With React

          本文链接:https://www.haomeiwen.com/subject/sipzfqtx.html