深入react技术栈--React数据流

150 阅读3分钟

导语

在本章,我们来学习一下 React数据流及其原理

数据流

在React中,数据是自顶向下的单向流动的,即从父组件到子组件。这条原则让组件之间的关系变得简单且可预测。

state与props是React 组件中最重要的概念。如果顶层组件初始化props, 那么React会向下遍历整棵组件树, 重新尝试渲染所有相关的子组件。而 state 只关心每个组件自己内部的状态,这些状态只能在组件内改变。把组件看成是一个函数,那么它接受了props作为参数,内部由 state作为函数的内部参数,返回一个 Virtual DOM实现。

state

React可以管理组件的内部状态。 在React中, 把这类状态统一称为 state.

当组件内部使用库内置的 setState 方法时, 最大的表现行为就是该组件会尝试重新渲染。 因为改变了内部状态。 比如:

import React, { Component } from 'react';

export default class Counter extends Component {
    constructor(props) {
        super(props);
	这里有一个比较有意思的点
        this.handleClick = this.handleClick.bind(this);

        this.state = {
            count: 0,
        };
    }

    handleClick(e) {
        e.preventDefault();

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

    render() {
        return (
            <div>
                <p>{this.state.count}</p>
                <button onClick={this.handleClick}>更新</button>
            </div>
        )
    }
}

React组件的方法为什么要用bind绑定this?
首先,React这是使用的ES6的 class, 它只是一种语法糖(只要它能实现的,es5也能实现) 而使用 class 创建的对象, 在没有通过 new 关键字去实例化之前, 它内部方法this是无绑定状态的。 也就是说上面的代码, handleClick 方法如果不做绑定, 那么这个方法的 this 会指向 undefined

还有一点值得注意, setState 是一个异步方法, 一个生命周期内所有的 setState 方法会合并操作。

props

props是React 中另一个重要的概念。组件的 props 一定来自于默认属性或通过父组件传递而来。 如果说要渲染一个对 props 加工后的值, 最简单的方法就是使用局部变量或直接在JSX中计算结果。

props传参

1.父组件调用子组件时传入属性 2.子组件直接调用this.props.属性名, 即可拿到父组件传递过来的值。

import React, { Component,Fragment} from 'react';

//React的props传参

// 父组件
class App extends Component {
  render() {
    return (
      <Fragment>
        <Child aaa="红牛"></Child>
      </Fragment>
    )
  }
}

// 子组件
class Child extends Component{
      render(){
        return (
          <div>{this.props.aaa}</div>
        )
      }
}

export default App;

props传递函数

  1. 在父组件里定义一个函数 2.调用子组件时将函数传递过去 3.子组件通过this.props.函数名()来调用函数并且执行
import React, { Component,Fragment} from 'react';

//React的props传参

// 父组件
class App extends Component {
  render() {
    return (
      <Fragment>
        <Child aaa="红牛" bbb={this.hanshu}></Child>
      </Fragment>
    )
  }
  hanshu(){
    return  "我是父组件传过来的函数"
}}

// 子组件
class Child extends Component{
      render(){
        return (
          <div>{this.props.aaa}{this.props.bbb()}</div>
        )
      }
}

export default App;

props验证

  1. 安装props-type
  2. 使用两个属性来进行验证
    • propTypes: 用来验证类型和是否必传
    • defaultProps: 用来设置未传参时的默认值
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';

export default class App extends Component {
    render() {
        return (
            <Fragment>
                <Child aaa="后牛" ccc="大后遭" />
            </Fragment>
        )
    }
}


class Child extends Component {
    render() {
        return (
            <div>
                <div>{this.props.aaa}</div>
                <div>{this.props.bbb}</div>
                <div>{this.props.ccc}</div>
                <div>{this.props.ddd}</div>
            </div>
        )
    }
}

// 对传过来的props进行验证
// 验证类型和是否必传

//这里其实是把Child当成了一个对象,直接设置对象的属性,和new实例化没有什么关系,可能容易误会
Child.propTypes = {
    aaa: PropTypes.number,
    bbb: PropTypes.isRequired,
    ccc: PropTypes.string.isRequired
}

Child.defaultProps = {
    ddd: "默认值"
}

解释:

  1. aaa类型传入为string, 期望为number
  2. bbb需要被传入

验证不通过会报错,但是实际上并不影响我们页面的正常显示

下面我们看看另一种写法

利用static静态属性将验证写在类的里面

import React, { Component,Fragment } from 'react';
import PropTypes from 'prop-types';

export default class App extends Component {
    render() {
        return (
            <Fragment>
                <Child aaa="红牛" ccc="大红枣"/>
            </Fragment>
        )
    }
}

class Child extends Component {

    static propTypes = {
        aaa: PropTypes.number,
        bbb: PropTypes.string.isRequired,
        ccc: PropTypes.string.isRequired
    }

    static defaultProps = {
        ddd: "默认值"
    }

    render() {
        return (
            <div>
                <div>{this.props.aaa}</div>
                <div>{this.props.bbb}</div>
                <div>{this.props.ccc}</div>
                <div>{this.props.ddd}</div>
            </div>
        )
    }
}