父子组件通信
大约 3 分钟约 983 字
类组件
父子组件通信
// Vote.jsx
import React from 'react'
import VoteMain from './VoteMain'
import VoteFooter from './VoteFooter'
class Vote extends React.Component {
state = {
supNum: 10,
oppNum: 0,
}
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'>
<div className='header'>
<h2 className='title'>React</h2>
<span className='num'>{supNum + oppNum}</span>
</div>
<VoteMain supNum={supNum} oppNum={oppNum}></VoteMain>
<VoteFooter change={this.change}></VoteFooter>
</div>
)
}
}
export default Vote
// VoteFooter.jsx
import { Button } from 'antd'
import React from 'react'
import PropTypes from 'prop-types'
class VoteFooter extends React.PureComponent {
static defaultProps = {}
static propTypes = {
change: PropTypes.func.isRequired,
}
render() {
console.log('footer Render')
let { change } = this.props
return (
<div className='footer'>
<Button type='primary' onClick={change.bind(null, 'sup')}>
支持
</Button>
<Button
type='primary'
danger
onClick={change.bind(null, 'opp')}
>
反对
</Button>
</div>
)
}
}
export default VoteFooter
// VoteMain.jsx
import React from 'react'
import PropTypes from 'prop-types'
class VoteMain extends React.Component {
static defaultProps = {
supNum: 0,
oppNum: 0,
}
static propTypes = {
supNum: PropTypes.number,
oppNum: PropTypes.number,
}
render() {
let { supNum, oppNum } = this.props
let ratio = '--'
let 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
上下文通信
// ThemeContext.js
import React from 'react'
const ThemeContext = React.createContext()
export default ThemeContext
// Vote.jsx
import React from 'react'
import VoteMain from './VoteMain'
import VoteFooter from './VoteFooter'
import ThemeContext from '../ThemeContext'
class Vote extends React.Component {
state = {
supNum: 10,
oppNum: 0,
}
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 (
<ThemeContext.Provider
value={{
supNum,
oppNum,
change: this.change,
}}
>
<div className='vote-box'>
<div className='header'>
<h2 className='title'>React</h2>
<span className='num'>{supNum + oppNum}</span>
</div>
<VoteMain></VoteMain>
<VoteFooter></VoteFooter>
</div>
</ThemeContext.Provider>
)
}
}
export default Vote
// VoteFooter.jsx
import { Button } from 'antd'
import React from 'react'
import ThemeContext from '../ThemeContext'
class VoteFooter extends React.Component {
render() {
return (
<ThemeContext.Consumer>
{(context) => {
let { change } = context
return (
<div className='footer'>
<Button
type='primary'
onClick={change.bind(null, 'sup')}
>
支持
</Button>
<Button
type='primary'
danger
onClick={change.bind(null, 'opp')}
>
反对
</Button>
</div>
)
}}
</ThemeContext.Consumer>
)
}
}
export default VoteFooter
// VoteMain.jsx
import React from 'react'
import ThemeContext from '../ThemeContext'
class VoteMain extends React.Component {
static contextType = ThemeContext
render() {
let { supNum, oppNum } = this.context
let ratio = '--'
let 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
函数组件
父子组件通信
// Vote.jsx
import React, { useState, useCallback } from 'react'
import VoteMain from './VoteMain'
import VoteFooter from './VoteFooter'
const Vote = function Vote() {
let [supNum, setSupNum] = useState(10)
let [oppNum, setOppNum] = useState(0)
const change = useCallback(
(type) => {
if (type === 'sup') {
setSupNum(supNum + 1)
return
}
setOppNum(oppNum + 1)
},
[supNum, oppNum]
)
return (
<div className='vote-box'>
<div className='header'>
<h2 className='title'>React</h2>
<span className='num'>{supNum + oppNum}</span>
</div>
<VoteMain supNum={supNum} oppNum={oppNum}></VoteMain>
<VoteFooter change={change}></VoteFooter>
</div>
)
}
export default Vote
// VoteFooter.jsx
import { Button } from 'antd'
import React, { memo } from 'react'
import PropTypes from 'prop-types'
const VoteFooter = function VoteFooter(props) {
console.log('Footer Render')
let { change } = props
return (
<div className='footer'>
<Button type='primary' onClick={change.bind(null, 'sup')}>
支持
</Button>
<Button type='primary' danger onClick={change.bind(null, 'opp')}>
反对
</Button>
</div>
)
}
VoteFooter.defaultProps = {}
VoteFooter.propTypes = {
change: PropTypes.func.isRequired,
}
export default memo(VoteFooter)
// VoteMain.jsx
import React, { useMemo } from 'react'
import PropTypes from 'prop-types'
const VoteMain = function VoteMain(props) {
let { supNum, oppNum } = props
let ratio = useMemo(() => {
let ratio = '--'
let total = supNum + oppNum
if (total > 0) ratio = ((supNum / total) * 100).toFixed(2) + '%'
return ratio
}, [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 VoteMain
上下文传值
// ThemeContext.js
import React from 'react'
const ThemeContext = React.createContext()
export default ThemeContext
// Vote.jsx
import React, { useState, useCallback } from 'react'
import VoteMain from './VoteMain'
import VoteFooter from './VoteFooter'
import ThemeContext from '../ThemeContext'
const Vote = function Vote() {
let [supNum, setSupNum] = useState(10)
let [oppNum, setOppNum] = useState(0)
const change = (type) => {
if (type === 'sup') {
setSupNum(supNum + 1)
return
}
setOppNum(oppNum + 1)
}
return (
<ThemeContext.Provider
value={{
supNum,
oppNum,
change,
}}
>
<div className='vote-box'>
<div className='header'>
<h2 className='title'>React</h2>
<span className='num'>{supNum + oppNum}</span>
</div>
<VoteMain supNum={supNum} oppNum={oppNum}></VoteMain>
<VoteFooter change={change}></VoteFooter>
</div>
</ThemeContext.Provider>
)
}
export default Vote
// VoteFooter.jsx
import { Button } from 'antd'
import React, { memo, useContext } from 'react'
import ThemeContext from '../ThemeContext'
const VoteFooter = function VoteFooter(props) {
console.log('Footer Render')
let { change } = useContext(ThemeContext)
return (
<div className='footer'>
<Button type='primary' onClick={change.bind(null, 'sup')}>
支持
</Button>
<Button type='primary' danger onClick={change.bind(null, 'opp')}>
反对
</Button>
</div>
)
}
export default memo(VoteFooter)
// VoteMain.jsx
import React, { useContext } from 'react'
import ThemeContext from '../ThemeContext'
const VoteMain = function VoteMain() {
let { supNum, oppNum } = useContext(ThemeContext)
return (
<div className='main'>
<p>支持人数:{supNum}人</p>
<p>反对人数:{oppNum}人</p>
</div>
)
}
// const VoteMain = function VoteMain() {
// return (
// <ThemeContext.Consumer>
// {(context) => {
// let { supNum, oppNum } = context
// return (
// <div className='main'>
// <p>支持人数:{supNum}人</p>
// <p>反对人数:{oppNum}人</p>
// </div>
// )
// }}
// </ThemeContext.Consumer>
// )
// }
export default VoteMain