深入浅出React和Redux——阅读笔记2

第二章 设计高质量的React组件

  1. 设计原则
    高内聚:把逻辑紧密相关的内容放在一个组件在
    低耦合:不同组件之间的依赖关系要尽量弱化,也就是说每个组件要尽量独立

差劲的程序员操心代码,优秀的程序员数据结构和它们之间的关系
——Linus Torvalds, Linux创始人

  1. prop 和 state
  • prop用于定义外部接口,state用于记录内部状态;
  • prop的赋值在外部世界使用组件时,state的赋值在组件内部;
  • 组件不应该改变prop的值,而state存在的目的就是让组件来改变的。

传递prop

import React, { Component } from "react";
import Counter from "./Counter.js";

// 定义样式
const style = {
  margin: "20px"
};

class ControlPanel extends Component {
  render() {
    console.log("enter ControlPanel render");
    return (
      // 使用样式
      
{/* 传递prop */}
); } } export default ControlPanel;
  1. prop初始化和类型定义
import React, { Component, PropTypes } from "react";

const buttonStyle = {
  margin: "10px"
};

class Counter extends Component {
  constructor(props) {
    console.log("enter constructor: " + props.caption);
    super(props);

    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
    // 定义state
    this.state = {
      count: props.initValue
    };
  }

  /* 已废弃的用法
  getInitialState() {
    console.log('enter getInitialState');
  }

  getDefaultProps() {
    console.log('enter getDefaultProps');
  }
  */

  render() {
    console.log("enter render " + this.props.caption);
    const { caption } = this.props;
    return (
      
{caption} count: {this.state.count}
); } } // 定义prop的类型以及是否为必须参数 Counter.propTypes = { caption: PropTypes.string.isRequired, initValue: PropTypes.number }; // 定义默认的prop值 Counter.defaultProps = { initValue: 0 }; export default Counter;
  1. 生命周期
    React有如下三个过程:
  • 装载过程(Mount),也就是把组件第一次在DOM树中渲染的过程;


    深入浅出React和Redux——阅读笔记2_第1张图片
    image.png
  • 更新过程(Update),当组件被重新渲染的过程;


    深入浅出React和Redux——阅读笔记2_第2张图片
    image.png
  • 卸载过程(Unmount),组件从DOM中删除的过程。


    image.png

具体生命周期函数如下:
• constructor(props) - 它在组件初始化时被调用。在这个方法中,你可以设置初始化状态以及绑定类方法。

• componentWillMount() - 它在 render() 方法之前被调用。这就是为什么它可以用作去设置组件内部的状态,因为它不会触发组件的再次渲染。但一般来说,还是推荐在 constructor() 中去初始化状态。

• render() - 这个生命周期方法是必须有的,它返回作为组件输出的元素。这个方法应该是一个纯函数,因此不应该在这个方法中修改组件的状态。它把属性和状态作为输入并且返回(需要渲染的)元素。

• componentDidMount() - 它仅在组件挂载后执行一次。这是发起异步请求去 API 获取数据的绝佳时期。获取到的数据将被保存在内部组件的状态中然后在 render() 生命周期方法中展示出来。

• componentWillReceiveProps(nextProps)-这个方法在一个更新生命周(updatelifecycle)中被调用。新的属性会作为它的输入。因此你可以利用 this.props 来对比之后的属性和之前的属性,基于对比的结果去实现不同的行为。此外,你可以基于新的属性来设置组件的状态。

• shouldComponentUpdate(nextProps, nextState) - 每次组件因为状态或者属性更改而更新时,它都会被调用。你将在成熟的 React 应用中使用它来进行性能优化。在一个更新生命周期中,组件及其子组件将根据该方法返回的布尔值来决定是否重新渲染。这样你可以阻止组件的渲染生命周期(render lifecycle)方法,避免不必要的渲染。

• componentWillUpdate(nextProps, nextState) - 这个方法是 render() 执行之前的最后一个方法。你已经拥有下一个属性和状态,它们可以在这个方法中任由你处置。你可以利用这个方法在渲染之前进行最后的准备。注意在这个生命周期方法中你不能再触发 setState() 。如果你想基于新的属性计算状态,你必须利用componentWillReceiveProps() 。

• componentDidUpdate(prevProps, prevState) - 这个方法在 render() 之后立即调用。你可以用它当成操作 DOM 或者执行更多异步请求的机会。

• componentWillUnmount() - 它会在组件销毁之前被调用。你可以利用这个生命周期方法去执行任何清理任务。

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

const buttonStyle = {
  margin: '10px'
};

class Counter extends Component {
  constructor(props) {
    console.log('enter constructor: ' + props.caption);
    super(props);

    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);

    this.state = {
      count: props.initValue
    };
  }

  /*
  getInitialState() {
    console.log('enter getInitialState');
  }

  getDefaultProps() {
    console.log('enter getDefaultProps');
  }
  */

  componentWillReceiveProps(nextProps) {
    console.log('enter componentWillReceiveProps ' + this.props.caption);
  }

  componentWillMount() {
    console.log('enter componentWillMount ' + this.props.caption);
  }

  componentDidMount() {
    console.log('enter componentDidMount ' + this.props.caption);
  }

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

  onClickDecrementButton() {
    this.setState({ count: this.state.count - 1 });
  }
  // 是否需要更新渲染,性能优化
  shouldComponentUpdate(nextProps, nextState) {
    return (
      nextProps.caption !== this.props.caption ||
      nextState.count !== this.state.count
    );
  }

  render() {
    console.log('enter render ' + this.props.caption);
    const { caption } = this.props;
    return (
      
{caption} count: {this.state.count}
); } } Counter.propTypes = { caption: PropTypes.string.isRequired, initValue: PropTypes.number }; Counter.defaultProps = { initValue: 0 }; export default Counter;
  1. 组件向外传递数据
    父组件向子组件传递一个函数,子组件调用函数并传参达到通知父组件的目的,父组件执行函数改变自身的值。
    父组件:
import React, { Component } from 'react';
import Counter from './Counter.js';

const style = {
  margin: '20px'
};

class ControlPanel extends Component {

  constructor(props) {
    super(props);

    this.onCounterUpdate = this.onCounterUpdate.bind(this);

    this.initValues = [ 0, 10, 20];

    const initSum = this.initValues.reduce((a, b) => a+b, 0);
    this.state = {
      sum: initSum
    };
  }

  onCounterUpdate(newValue, previousValue) {
    const valueChange = newValue - previousValue;
    this.setState({ sum: this.state.sum + valueChange});
  }

  render() {
    return (
      

Total Count: {this.state.sum}
); } } export default ControlPanel;

子组件:

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

const buttonStyle = {
  margin: '10px'
};

class Counter extends Component {

  constructor(props) {
    super(props);

    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);

    this.state = {
      count: props.initValue
    }
  }

  onClickIncrementButton() {
    this.updateCount(true);
  }

  onClickDecrementButton() {
    this.updateCount(false);
  }

  updateCount(isIncrement) {
    const previousValue = this.state.count;
    const newValue = isIncrement ? previousValue + 1 : previousValue - 1;

    this.setState({count: newValue})
    this.props.onUpdate(newValue, previousValue)
  }

  render() {
    const {caption} = this.props;
    return (
      
{caption} count: {this.state.count}
); } } Counter.propTypes = { caption: PropTypes.string.isRequired, initValue: PropTypes.number, onUpdate: PropTypes.func }; Counter.defaultProps = { initValue: 0, onUpdate: f => f //什么都不做的函数 }; export default Counter;

你可能感兴趣的:(深入浅出React和Redux——阅读笔记2)