1. props 传递数据
  2. props 传递函数
    1. 以属性方式传递数据和函数
    2. 函数组价默认没有 state
  3. props 类型检查
  4. defaultProps 推荐使用静态属性定义,不推荐在 class 外进行定义
  5. 在react中可以定义默认props,使用es5时,可以使用getDefaultProps
    1. const App = React.createClass({
    2. getDefaultProps: function() {
    3. return {
    4. name: 'demo'
    5. }
    6. },
    7. render: function() {
    8. return <h1>This is my {this.props.name}</h1>
    9. }
    10. })

class组件模板

  1. propTypes & defaultProps
    1. 所有的组件都应该有prop types
    2. propTypesdefaultProps是静态属性 static
    3. 尽可能在组件类的的前面定义,让其他的开发人员读代码的时候可以立刻注意到。起到文档的作用
  2. 箭头函数会自动维护正确的上下文, this
    1. 类方法
    2. 类属性
  3. this.setState 默认是异步的,推荐使用函数的写法
    1. this.setState((state, props)=> ({ }))
    2. react会把多次调用的setState放在一起调用
    3. 调用了setState之后state不一定会立即改变,函数可以获取最新的 state的值,推荐使用函数写法
  4. 本地引入的import 和全局的 import会用一个空行来分割
    1. const 写在 import的后面
    2. 先引入全局的 import,后引入 本地的 import
  1. import React, { Component } from 'react'
  2. import PropTypes from 'prop-types'
  3. import styles from './style.scss'
  4. class Parent extends Component {
  5. state = { // 设置初始状态
  6. visible: false
  7. }
  8. static propTypes = {
  9. title: PropTypes.string,
  10. data: PropTypes.array.isRequired,
  11. }
  12. static defaultProps = {
  13. data: [],
  14. title: ''
  15. }
  16. handleChange = (e) => {
  17. e.preventDefault()
  18. const value = e.target.value
  19. this.props.onClick(value)
  20. }
  21. handleClick = () => {
  22. this.setState(state => ({visible: !state.visible }))
  23. }
  24. render () {
  25. // 多行的props的,每一个prop都应该单独占一行,Prettier 格式化
  26. const {
  27. data,
  28. title
  29. } = this.props
  30. return (
  31. <div>
  32. <h1>{title}</h1>
  33. </div>
  34. )
  35. }
  36. }
  37. export default Parent

装饰器语法

  1. 装饰器语法 Decorator
  2. 装饰器就是把类组件作为一个参数传入了一个方法
  3. https://javascript.info/call-apply-decorators
    ```jsx import React, { Component } from ‘react’ import PropTypes from ‘prop-types’ import { observer } from ‘mobx-react’

import styles from ‘./style.scss’

@observer class Parent extends Component {}

export default Parent

// 不用装饰器的写法 class Parent extends Component {} export default observer(Parent)

  1. <a name="CPVzU"></a>
  2. ### 子组件
  3. 1. 避免在子组件中传入闭包 Closures<br />
  4. 2. 原因:每次父组件 render 的时候,都会新建一个新的函数并传递给 input
  5. 1. 如果`input`是一个React组件,会自动触发组件的重绘 re-render,不管其他的props是否发生了改变<br />
  6. ```jsx
  7. handleChange = (e) => {
  8. const value = e.target.value
  9. this.setState(() => ({ value }))
  10. }
  11. <Input
  12. value=""
  13. onChange={ e => this.handleChange(e) }
  14. // onChange={ e => this.setState({ value: e.target.value }) } // 闭包,不推荐的写法
  15. />

函数组件

  1. Functional Components 没有state,没有props,也没有方法,是一个纯函数的组件
  2. 在组件的声明之前就定义了propTypes
  3. 组件就是一个方法(函数),参数就是props
  4. 函数组件没法使用装饰器,只能把函数作为参数传入别的函数里面
    1. UI组件和容器组件
  1. import React from 'react'
  2. import PropTypes from 'prop-types'
  3. import { observer } from 'mobx-react'
  4. import styles from './styles.css'
  5. Child.propTypes = {
  6. expanded: PropTypes.bool,
  7. onSubmit: PropTypes.func.isRequired,
  8. onExpand: PropTypes.func.isRequired
  9. }
  10. function Child (props) {
  11. const { children, onSubmit, onExpand, expand = false } = props
  12. return (
  13. <form style={styles.form} onSubmit={onSubmit}>
  14. {children}
  15. <button onClick={onExpand}>Expand</button>
  16. </form>
  17. )
  18. }
  19. // 代替装饰器语法:把函数作为参数传入到其他的函数里面
  20. export default observer(Child)

const匿名函数

  1. 如果Babel配置错误,组件里的任何错误都显示为发生在 <>里的,调试起来就非常麻烦
  2. 匿名方法也会引起 Jest其他的问题。由于会引起各种难以理解的问题,推荐使用function,少使用const ```jsx // 推荐的用法 function Child (props) {}

// 不推荐的用法 const Child = ({ onExpand, expanded, children }) => {}

  1. <a name="65gFa"></a>
  2. ### 多个if判断
  3. 1. 多个 if条件判断,根据不同的条件渲染不同组件,用匿名函数自执行,来达到使用 if...else 的目的<br />
  4. 2. `{ (() => {})() }`<br />
  5. 3. 用大括号包起来的[IIFE] 匿名函数自执行,然后把`if`表达式都放进去。返回你要返回的组件
  6. 1. 大量使用立即执行函数会造成性能上的损失<br />
  7. ```jsx
  8. // { (() => {})() }
  9. <div>
  10. {
  11. (() => {
  12. if (visible) {
  13. return <h1></h1>
  14. }
  15. else {
  16. return <Empty />
  17. }
  18. })()
  19. }
  20. </div>


es6 constructor初始化

  1. import React from 'react'
  2. import PropTypes from 'prop-types'
  3. export default class Parent extends React.Component {
  4. constructor(props) {
  5. super(props);
  6. this.state = {count: props.count}
  7. }
  8. onClick() {
  9. this.setState(state => ({count: state.count + 1}) );
  10. }
  11. render() {
  12. return (
  13. <div onClick={this.onClick.bind(this)}>
  14. Clicks: {this.state.count}
  15. </div>
  16. );
  17. }
  18. }
  19. Parent.propTypes = { count: PropTypes.number };
  20. Parent.defaultProps = { count: 0 }


es7初始化

  1. 推荐使用 es7的语法
    1. ES7 is better because it enables the following scenarios
    2. https://stackoverflow.com/questions/35662932/react-constructor-es6-vs-es7
  2. es7 class语法
    1. https://github.com/tc39/proposal-class-fields
  3. 用 redux时,要 export defaut redux
  1. import React from 'react'
  2. import PropTypes from 'prop-types'
  3. export default class Parent extends React.Component {
  4. static propTypes = { count: PropTypes.number }
  5. static defaultProps = { count: 0 }
  6. state = { count: this.props.count }
  7. onClick = () => {
  8. this.setState(state => ({ count: state.count + 1 }) );
  9. }
  10. render() {
  11. return (
  12. <div onClick={this.onClick}>
  13. Clicks: {this.state.count}
  14. </div>
  15. )
  16. }
  17. }

class组件

  1. class 必须继承 React.Component 或 React.PureComponent
  2. class内部必须有 render方法
    1. render方法返回 jsx
  1. import React, { PureComponent } from 'react'
  2. import PropTypes from 'prop-types'
  3. import classnames from 'classnames'
  4. import './index.less'
  5. class Todo extends PureComponent {
  6. constructor (props) {
  7. super(props)
  8. this.state = {
  9. user: ''
  10. }
  11. }
  12. // 默认 props参数类型约束
  13. static propTypes = {
  14. className: PropTypes.string,
  15. style: PropTypes.object,
  16. data: PropTypes.array,
  17. allowClear: PropType.bool
  18. }
  19. // 默认 props参数
  20. static defaultProps = {
  21. className: '',
  22. style: {},
  23. data: [],
  24. allowClear: true
  25. }
  26. // 推荐使用静态方法来绑定事件
  27. handleChange = (id, title, ev) => {
  28. // this 默认 undefined
  29. }
  30. render () {
  31. const { data, fetching, className, style, ...attr } = this.props
  32. const loading = fetching ? <Spin size="small" /> : ''
  33. const cls = classnames('loading', {
  34. [className]: true,
  35. })
  36. return (
  37. <>
  38. <header onClick="this.handleClick">Parent</header>
  39. </>
  40. )
  41. }
  42. }


props

  1. props来进行父子组件传参
  2. 父组件调用子组件时传入属性
    1. 子组件直接通过 this.props.属性名 拿到父组件传过来的值
  3. 在父组件里定义一个函数,调用子组件时将函数传过去
    1. 子组件通过 this.props.函数名() 来调用函数并且执行
    2. prop-types 对父级传参进行验证


默认 props

  1. 设置静态属性 static defaultProps,默认的 props参数
  2. 只能在 class组件中设置
  1. class MyDemo extends React.PureComponent{
  2. constructor(props){
  3. super(props)
  4. }
  5. //如果babel设置为es6的转码方式会报错,ES6的class中只有静态方法,没有静态属性。
  6. // 因为定义静态属性不属于es6,而在es7的草案中。
  7. static defaultProps = { // props 默认值
  8. user:"默认值"
  9. }
  10. render(){
  11. return <h1>This is {this.props.name}</h1>
  12. }
  13. }


static 静态属性

  1. 如果babel设置为es6的转码方式,会报错
    1. 因为定义静态属性不属于es6,而在es7的草案中
    2. ES6的class中只有静态方法,没有静态属性
  2. 由于是用ES6 class语法创建组件,其内部只允许定义方法,而不能定义属性
  3. class的属性只能定义在class之外。所以defaultProps要写在组件外部 ```jsx class App extends React.Component { constructor(props) { super(props); } render() { return

    This is my {this.props.name}

    } }

//由于是用ES6 class语法创建组件,其内部只允许定义方法,而不能定义属性,class的属性只能定义在class之外。所以defaultProps要写在组件外部。 App.defaultProps = { name: ‘demo’ }

  1. <br />
  2. <a name="R65oh"></a>
  3. ## class组件优化
  4. 1. class类组件中,只要调用setState就会触发render
  5. 2. 父组件state改变时,如果子组件接受的参数并没有变化,那么子组件是不会重新渲染的<br />
  6. 1. 子组件根本没有接收参数,自然也不会产生性能优化问题;
  7. 1. 所以,子组件传值,不要多传值,不然只要这个值改变就会触发重新渲染<br />
  8. 2. 在传递props/state时,只传递需要的参数<br />
  9. 2. 子组件通过 `componentWillReceiveProps` 生命周期方法,将接收的 props转换为子组件的 state,不推荐使用<br />
  10. 3. hooks函数组件 memo的第二个参数
  11. 1. 上一次的 props 和 这一次 props,返回true/false<br />
  12. <br />
  13. <a name="7f612e76"></a>
  14. ## webpack配置
  15. 1. 如果使用webpack的话,加入stage-0后就能尝试es7语法了,static也能在class内部定义属性
  16. ```jsx
  17. loaders:[
  18. {
  19. test: /\.js[x]?$/,
  20. exclude: /node_modules/,
  21. loader: 'babel-loader' ,
  22. query:{
  23. presets:['es2015','stage-0','react'],
  24. plugins:['transform-runtime']
  25. },
  26. }
  27. ]
  1. 如果报错,因为static本是es7中的草案,要想使用static需要做一些配置
  2. 首先,确保安装了babel-preset-react、babel-core、babel-loader、babel-preset-es2015
  3. 如果没有安装,就执行如下语句 ```jsx npm install babel-core babel-loader babel-preset-es2015 babel-preset-react —save-dev

// 然后安装 babel-preset-stage-0 es7草案语法 npm install —save-dev babel-preset-stage-0

// 之后配置webpack.config.js let path = require(‘path’); let webpack = require(‘webpack’);

module.exports = { entry: dirname+’/src/entry.js’, output: { path: dirname+’/dist’, filename: ‘bundle.js’ }, devtool: ‘source-map’, resolve: {//指定可以被import的文件名后缀 extensions: [‘.js’, ‘.jsx’,’.sass’,’.ts’] }, module: { loaders: [ { test: /.js?$/, exclude: /(node_modules|bower_components)/, loader: ‘babel-loader’, query: { presets: [‘es2015’, ‘react’,’stage-0’] } //将react编译成js文件 }, { test: /.css$/, loader: ‘style-loader!css-loader’ }, //打包css文件 { test: /.scss$/, loader: ‘style!css!sass?sourceMap’}, //编译sass文件 { test: /.(png|jpg)$/, loader: ‘url-loader?limit=8192’} //对图片进行打包 ] }, //4、服务器依赖包配置 devServer: {//注意:网上很多都有colors属性,但是实际上的webpack2.x已经不支持该属性了 contentBase: “./dist”,//本地服务器所加载的页面所在的目录 historyApiFallback: true,//不跳转 inline: true//实时刷新 } } ```