React 父子组件传值

204 阅读1分钟

函数组件

父组件:Vote.jsx

import React, { useState, useCallback } from 'react'
import VoteMain from './VoteMain'
import VoteFooter from './VoteFooter'
import './Vote.less'

const Vote = function Vote() {
  let [supNum, setSupNum] = useState(10),
    [oppNum, setOppNum] = useState(5)

  const change = useCallback(
    (type) => {
      if (type === 'sup') {
        setSupNum(supNum + 1)
        return
      }
      setOppNum(oppNum + 1)
    },
    [supNum, oppNum]
  )

  return (
    <div className="vote-box">
      <header className="header">
        <h2 className="title">React真的很不错!!</h2>
        <span className="num">{supNum + oppNum}人</span>
      </header>
      <VoteMain supNum={supNum} oppNum={oppNum} />
      <VoteFooter change={change} />
    </div>
  )
}
export default Vote

子组件1:VoteMain.jsx

import React, { memo, useMemo } from 'react'
import PropTypes from 'prop-types'

const VoteMain = function VoteMain(props) {
  let { supNum, oppNum } = props

  let ratio = useMemo(() => {
    let total = supNum + oppNum
    return total > 0 ? ((supNum / total) * 100).toFixed(2) + '%' : '--'
  }, [supNum, oppNum])

  return (
    <div className="main">
      <p>支持人数:{supNum}人</p>
      <p>反对人数:{oppNum}人</p>
      <p>支持比率:{ratio}</p>
    </div>
  )
}
// 属性规则校验
VoteMain.defaultProps = {
  supNum: 0,
  oppNum: 0,
}
VoteMain.propTypes = {
  supNum: PropTypes.number,
  oppNum: PropTypes.number,
}
export default memo(VoteMain)

子组件2:VoteMain.jsx

import React, { memo } from 'react'
import PropTypes from 'prop-types'

const VoteFooter = function VoteFooter(props) {
  let { change } = props
  return (
    <div className="footer">
      <button onClick={change.bind(null, 'sup')}>支持</button>
      <button onClick={change.bind(null, 'sup')}>反对</button>
    </div>
  )
}
// 属性规则校验
VoteFooter.propTypes = {
  change: PropTypes.func.isRequired,
}
export default memo(VoteFooter)

优化:useCallback memo useMemo

image.png

类组件

父组件:Vote.jsx

import React from 'react'
import VoteMain from './VoteMain'
import VoteFooter from './VoteFooter'
import './Vote.less'

class Vote extends React.Component {
  // 定义状态
  state = {
    supNum: 10,
    oppNum: 5,
  }
  // 修改状态的方法:箭头函数可以保证方法中的this永远是父组件的实例
  change = (type) => {
    let { supNum, oppNum } = this.state
    if (type === 'sup') {
      this.setState({ supNum: supNum + 1 })
      return
    }
    this.setState({ oppNum: oppNum + 1 })
  }
  render() {
    let { supNum, oppNum } = this.state
    return (
      <div className="vote-box">
        <header className="header">
          <h2 className="title">React真的很不错!!</h2>
          <span className="num">{supNum + oppNum}人</span>
        </header>
        <VoteMain supNum={supNum} oppNum={oppNum} />
        <VoteFooter change={this.change} />
      </div>
    )
  }
}
export default Vote

子组件1:VoteMain.jsx

import React from 'react'
import PropTypes from 'prop-types'

class VoteMain extends React.PureComponent {
  /* 属性规则校验 */
  static defaultProps = {
    supNum: 0,
    oppNum: 0,
  }
  static propTypes = {
    supNum: PropTypes.number,
    oppNum: PropTypes.number,
  }

  render() {
    let { supNum, oppNum } = this.props
    let ratio = '--',
      total = supNum + oppNum
    if (total > 0) ratio = ((supNum / total) * 100).toFixed(2) + '%'

    return (
      <div className="main">
        <p>支持人数:{supNum}人</p>
        <p>反对人数:{oppNum}人</p>
        <p>支持比率:{ratio}</p>
      </div>
    )
  }
}
export default VoteMain

子组件2:VoteMain.jsx

import React from 'react'
import PropTypes from 'prop-types'

class VoteFooter extends React.PureComponent {
  /* 属性规则校验 */
  static propTypes = {
    change: PropTypes.func.isRequired,
  }

  render() {
    let { change } = this.props
    return (
      <div className="footer">
        <button onClick={change.bind(null, 'sup')}>支持</button>
        <button onClick={change.bind(null, 'opp')}>反对</button>
      </div>
    )
  }
}
export default VoteFooter

优化:pure component 减少不必要的更新

image.png image.png