父操作子
思路:获取子组件节点直接进行操作
父组件
//父组件
import React,{ Component,creatRef} from 'react'
import Son from './son'
export default class Father extends Component{
constructor(props) {
super()
this.changeSon = creatRef()
}
//父组件的函数
changeURL = () => {
//父组件通过ref拿可以访问子组件内的所有属性和方法并对其进行操作
this.changeSon.current.setState({ URL:'./src'}) //改变子组件url
this.changeSon.current.changeSize() //触发子组件的过度函数
}
render(){
return (
<>
<button onclick={()=>this.changeURL()}></button>
<Son ref={this.changeSon} />
</>
)
}
}
操作子组件
import React,{ Component,creatRef} from 'react'
export default class Son extends Component{
constructor(props) {
super()
this.state={
URL:'./img'
}
this.son = creatRef()
}
//子组件函数
changeSize = () => {
//图片放大2倍
this.son.current.transform='scale(2)'
//动画过渡 1s
this.son.current.transition='all 1s'
}
render(){
return (
<div>
<img
ref={this.son}
src={this.state.URL}
onClick={()=>this.changeSize()} />
</div>
)
}
}
子操作父
思路:通过回调函数对父组件的状态更新
父组件
//父组件
import React,{ Component } from 'react'
import Son from './son'
export default class Father extends Component{
constructor(props) {
super()
this.state ={
type:false
}
}
//父组件的函数传递到子组件 子调用后赋值
callBackValue = e => {
this.setState({type:e})
}
render(){
const { type } = this.state
return (
<>
{/* 根据子的布尔,父展示不同的值 */}
{type?'今天熬夜吧':'算了还是睡觉吧'}
<Son
type={type}
//bind指定作用域
callBackValue={this.callBackValue.bind(this)}
/>
</>
)
}
}
子组件
//父组件
import React,{ Component } from 'react'
export default class Son extends Component{
constructor(props) {
super()
//子组件的布尔值
this.state ={
type:false
}
}
//钩子函数,类似于vue的 created,挂载前操作
componentDidMount(){
//把父组件传递的 type 解构出来
const { type } = this.props
//赋值给子组件的type
this.setState({ type })
}
callBakcFahter = () => {
const { type } = this.state
//父组件传递的回调函数从props内解构
const { callBackValue } = this.props
let newCheckBoolean = !type
//解构出来子的type 赋值变量,然后通过setState 对type重新赋值取反,并将新得值通过回调函数更新到父组件内
this.setState({
type:newCheckBoolean
})
//回调传递
callBackValue(newCheckBoolean)
}
render(){
const { type } = this.state
return (
<>
子组件
<input type='checkbox' checked={type} onChange={ () =>this.callBakcFahter() }/>
</>
)
}
}
兄弟传值
思路:通过父组件中转,兄弟组件内,将公用的值进行更新后传递到父组件,再通过生命周期getDerivedStateFromProps进行同步,达到兄弟传值的效果
//父组件
import React,{ Component } from 'react'
export default class Father extends Component{
constructor(props) {
super()
this.state ={
showArr:[1,2,3,4,5 ]
}
}
upDateArr = v => {
let newV = v.length?v.split:['暂无数据']
this.setState({showArr:newV })
}
render(){
const { showArr } = this.state
return (
<>
{/* 一号兄弟 */}
<SonOne upDateArr={this.upDateArr.bind(this)} / >
{/* 二号兄弟 */}
<SonTwo showArr={showArr} / >
</>
)
}
}
一号兄弟修改值
//一号兄弟组件
import React,{ Component } from 'react'
export default class SonOne extends Component{
constructor(props) {
super()
this.state ={
showArr :[{key:'123'},{key:'456'},{key:'789'}],
}
}
upDateArr = v => {
this.setState({showArr:v})
}
render(){
const { showArr } = this.state
return (
<>
<table>
<thead>
<tr>
<th>当前数组</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{showArr && showArr.map(item=>{
return(
<tr key={item.key}>
<td> {item.key} </td>
<td>
<button onClick={()=> this.props.upDateArr(item.key)}>
展示当前数据
</button>
</td>
</tr>
)
})}
</tbody>
</table>
</>
)
}
}
二号兄弟同步更新值
//父组件
import React,{ Component } from 'react'
export default class SonOne extends Component{
constructor(props) {
super()
this.state ={
showArr:[],
}
}
// 加载更新state
componentDidMount(){
//解构父传递的值更新到自己
const { showArr } = this.props
this.setState({showArr})
}
//生命周期,会检测自己的状态与父的状态 nextProps==父 prevState==自己
static getDerivedStateFromProps(nextProps,prevState){
//判断父的值与当前 组件值是否相等,不等则进行更新
if(nextProps.showArr !== prevState.showArr){
return{
showArr:nextProps.showArr
}
}
return null
}
//更新后调用的生命周期 当前的props 和当前的state
componentDidUpdate(prevProps,prevState){
if(prevProps.showArr !== this.props.showArr){
alert("同步完成")
}
}
render(){
const { showArr } = this.state
return (
<>
兄弟二号
<span>
{ showArr }
</span>
</>
)
}
}
组合实现代码之间组件复用
有些组件我们无法提前知晓他们子组件内的具体内容,建议这些组件使用一个特殊的children props来将他们的子组件传递到渲染的结果中,当然我们也可以通过自行约定来使用,而不用通过children。
使用children
function Test(props){
return(
<div>
{props.children}
</div>
)
}
function hello(){
return (
<div>
<Test>
<h1>你好啊</h1>
<button>666</button>
</Test>
<Test>
<h1>999</h1>
<button>111</button>
</Test>
</div>
)
}
自行约定
//组件1
function IMG(){
return(
<img src={URL}/>
}
//组件2
function Title(){
return(
<div>标题:{title}</div>
)
}
//预定组件
export default function Test (props){
return(
<div>
{props.top}
{props.bottom}
</div>
)
}
//使用约定
render(){
<div>
<Test top={<IMG/>} bottom={<Title title='标题1'>} />
</div>
}
生命周期
生命周期指的是挂载,更新和销毁三个阶段,三个阶段内可以插入预设的函数来修改部分逻辑和操作dom达到预期效果。
生命周期三个状态:
1.Mounting(挂载): 已经插入真实DOM
2.Updating(更新): 正在被重新渲染
3.Unmounting(卸载):已经移除真实DOM
挂载:
当组件实例被创建并插入 DOM 中时,其生命周期调用顺序:
如果是父子组件,则先进行 父的render ---> 子render ---> 子cpdm---> 父cpdm的顺序
1.constructor():在React组件挂載之前,会调用它的构造函数(在react组件挂在前,会调用它的构造函数,在为React.component子类实现构造函数时,应在其他语句之前调用红super(props),否则在this.props构造函数中可能会出现未定义的BUG)
2. static getDerivedstateFromProps():在调用render 方法之前调用,并旦在初始挂载及后续更新时都会被调用,常用于兄弟组件更新时。
3. render():render() 方法是 class 组件中唯一必须实现的方法。
render(函数应该为纯函数,这意味着在不修政组件state 的情况下 每次调用时都返回相同的结果,并且它不会直接与浏览器交互。
如需与浏览器进行交互,请在componentDidmount(或其他生命周期方法中执行你的操作)
4.componentDidvount():在组件挂载后(插入DOM 树中)立即调用。
如果cpd()内调用的函数内有this.setState()操作,那么会重新调用render()
更新:
每当组件的state 或 props 发生变化时,组件就会更新。
当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
1.getperivedstateFromProps():在调用render方法之前调用,并且在初始挂载及后续更新时都会被调用。根据 shouldcomponentUpdate()的返回值,判断 React 组件的输出是否受当前 state
或 props 更改的影响。
componentDidupdate()不可以直接使用,会导致死循环
2.shouldcomponentupdate();当 props 或state 发生变化时,shouidcomponentUpdate() 会在渲染执行之前被调用。如果shouldcomponentupdate返回了false,则不会触发render调用和componentDidupdate()
3.render():render()方法是class 组件中唯一必须实现的方法。
4.getsnapshotBeforeupdate():在最近一次渲染输出(提交到 DOM 节点)之前调用。
5.componentDidupdate():state状态发生改变后调用。
卸载:
当组件从DOM中移除时会调用如下方法:
componentWillUnmount():在组件卸载及销毁之前调用
//常用的清除定时器操作
constructor(props) {
super()
this.timer = null
}
componentDidMount(){
this.timer = setInterval(()=>{
console.log( new Date().getTime())
},100)
}
componentWillUnmount(){
clearInterval( this.timer )
}
错误处理:
当渲染过程,生命周期,子组件的构造函数抛出错误时,会调用如下方法:
1. static getDeriveStateFromError()
2.componentDidCatch()