react18之 02 函数组件与类组件 父子props传值、props-type对props的限制、ref获取dom节点

react18之 02 函数组件与类组件 父子props传值、props-type对props的限制、ref获取dom节点

props

1:函数组件

1-1 函数组件传值
1-1-1 父组件
import React, { Component } from 'react';
import Fat from "./Fat";

export default class app extends Component {
 state = {
  name:'我是app'
 }
 componentDidMount() {}
 // 父组件的方法 传递到子组件 changeName={this.changeName}
 changeName = ()=>{
  let { name } = this.state
  name = name + '_'
  this.setState({name})
 }
 render(){
  const { name } = this.state
   return (
     <div>
      app
      <Fat name={name} changeName={this.changeName}></Fat>
     </div>
   )
 }
}

1-1-2 子组件 Fat.jsx
import React, { useEffect } from 'react';

export default function Fat(props) {
  // 01:使用props 接受父组件 向子组件传递值
  const { name,changeName } = props
    console.log('props',props);
    useEffect(() => {
        console.log('函数组件来咯')
    }, [])
    // 02:子组件 向父组件传值 => 通过调用父组件的方法
    const changeName1 = ()=>{
      changeName()
    }
    return (
        <div className='content'>
          Fat - { name }
          <div>
            我是修改父组件app的 <button onClick={changeName1}>修改</button>
          </div>
        </div>
    )
}
1-1-3 上述的效果

在这里插入图片描述

2:类组件

2-1 类组件案例 react 之简单的评论功能实现(增删)

在这里插入图片描述

  • 安装校验
    • npm i --save prop-types
app.jsx
  • 父组件的数据,需要在父组件之中操作!
import React, { Component } from "react";
import Add from "./Add";
import List from "./List";
export default class App extends Component {
  state = {
    list:[],
  }
  // 接收子组件的数据 修改当前组件数据
  addContent = (params) =>{
    let {list} = this.state
    list.push(params)
    this.setState({
      list
    })
  }
  // 接收子组件的数据 修改当前组件数据
  removeItem = (id)=>{
    // console.log('removeItem',id);
    let {list} = this.state
    list = list.filter(item=>item.id !== id)
    this.setState({
      list
    })
  }
  render() {
    const { list } = this.state
    return (
      <div className="App">
        <Add addContent={this.addContent}></Add>
        <List list={list} removeItem={this.removeItem}></List>
      </div>
    );
  }
}

Add.jsx
  • 使用prop-types 去校验父组件传递到子组件的值!
import PtopTypes from "prop-types";
import React, { Component } from "react";
export default class Add extends Component {
  static props = {
    addContent:PtopTypes.func.isRequired
  }
  state = {
    username: "",
    content: "",
    id:''
  };
  usernameChange = (event) => {
    let username = event.target.value
    this.setState({username})
  };
  contentChange = (event) => {
    let content = event.target.value
    this.setState({content})
  };
  submit = () => {
    let submitObj = this.state;
    this.props.addContent({...submitObj,id: +new Date()}) // 调用父组件的方法 传递数据 addContent方法 submitObj向父组件传递数据
    this.setState({
      username: "",
      content: "",
      id:''
    })
  }
  render() {
    let { username,content } = this.state;
    return (
      <div className="App">
        <div>
          <div >
            用户名:
            <input type="text" placeholder="用户名" value={username} onChange={this.usernameChange}></input>
          </div>
          <div style={{margin:'10px 0'}}>
            内容:
            <textarea placeholder="内容" value={content} onChange={this.contentChange}></textarea>
          </div>
          <button onClick={this.submit}>
            提交
          </button>
        </div>
      </div>
    );
  }
}
List.jsx
import PtopTypes from "prop-types";
import React, { Component } from "react";
import ListItem from "./ListItem";
export default class List extends Component {
  static props = {
    list:PtopTypes.object.isRequired,
    removeItem:PtopTypes.func.isRequired,
  }

  render() {
    const { list,removeItem } = this.props
    return (
      <div>
        {
          list.map((item,idx)=>{
            return (
              // removeItem={removeItem} 向子组件 传递方法
              <ListItem itemData={item} key={idx} removeItem={removeItem}></ListItem>
            )
          })

        }
      </div>
    );
  }
}

ListItem .jsx
import PtopTypes from "prop-types";
import React, { Component } from "react";

export default class ListItem extends Component {
  static props = {
    itemData:PtopTypes.object.isRequired,
    removeItem:PtopTypes.func.isRequired
  }
  // 子组件的点击方法 拿到id值后 调用父组件的方法
  delItem = ()=>{
    const { id } = this.props.itemData
    // console.log('id',id);
    this.props.removeItem(id) // 调用父组件方法
  }
  render() {
    const { itemData } = this.props
    return (
      <div style={{ marginBottom: "10px", background: "#ccc" }}>
        <div>
          username - { itemData.username }
        </div>
        <div>
         content - { itemData.content }
        </div>
        <button onClick={this.delItem}>删除</button>
      </div>
    );
  }
}

3:props传递使用 prop-types 对参数进行限制

  • npm i --save prop-types
3-1 常规的限制
3-1-1 Props.jsx
import React, { useState } from 'react';
import PropsSon from "./PropsSon"
export default function Props(props) {
    const [count,setCount] = useState(0);
    const name = '我是name'
    const bool = true
    const arr = [1,2,3]
    const obj = {
      name:'pp',
      age:20
    }
    
    function addCount(num){
      const increment = num === 0 || typeof num === 'number' ? num : 1;
      const res = count * 1 + increment;
      setCount(res)
    }
    return (
        <div className='content'>
          <div>
            Props父组件 <button onClick={addCount}>addCount</button>
          </div>
          <PropsSon count={count} name={name} 
            bool={bool} addCount={addCount}
            arr={arr} obj={obj}
            content={<span>我是通过element传递渲染的</span>}
          >
            <div>我是元素插槽,通过node渲染的</div>
          </PropsSon>
        </div>
    )
}
3-1-2 PropsSon.jsx
import React from 'react';
import PropsTypes from "prop-types"

export default function PropsSon(props) {
    const { count,name,bool,addCount,arr,obj,children,content  } = props

    function addCountSon(){
      addCount(2)
    }

    return (
        <div className='content'>
          PropsSon子组件 
          <div>
           count - {count}<br/>
           name - {name}<br/>
           bool - {bool ? 'true' : 'false'}<br/>
           addCount - 修改父组件的数据 <button onClick={addCountSon}>addCount+2</button><br/>
           arr - {arr}<br/>
           obj - {obj.name}-{obj.age}-{obj.sex}<br/>
           children  - {children } <br/>
           content - {content}<br/>
          </div>
        </div>
    )
}
// 对count的限制 必填 类型为数字,默认值为0
PropsSon.propTypes = {
  xxx: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), 支持number和string类型
  count: PropsTypes.number.isRequired, // 必填限制,类型为数字
  name: PropsTypes.string, // 类型为字符串 不必填
  bool: PropsTypes.bool, // 类型为布尔值 不必填
  addCount: PropsTypes.func.isRequired, // 必填限制,类型为函数
  arr: PropsTypes.array, // 类型为数组 不必填
  obj: PropsTypes.shape({
    name: PropsTypes.string.isRequired,
    age: PropsTypes.number.isRequired,
    sex: PropsTypes.string,
  }).isRequired,
  children: PropsTypes.node, // 任何可被渲染的元素(数字、字符串、元素、Fragment代码片段组件啥)
  content: PropsTypes.element, // 渲染react的 标签元素 dom节点等
};
PropsSon.defaultProps = {
  count: 0, // 默认值为 0
  bool: false, // bool的默认值为 false
  obj:{
    name: 'pp',
    age: 20,
    sex:'男'
  }
};

3-1-3 效果

在这里插入图片描述

ref 调用子组件的方法 与 获取子组件的数据

类组件

app.jsx 父组件
import React, { Component } from 'react';
import SonFuc from "./fucSon";
import Son from "./son";
export default class app1 extends Component {
// childRef = null
childRef =  React.createRef()
childFucRef = null
handleNameUpdate = (updatedName) => {
  console.log('updatedName',updatedName);
}
// 父组件 使用 ref 调用类组件 - 子组件的方法 通过cb回调函数拿到当前最新的子组件的数据
chanegSonName = () => {
  this.childRef.current && this.childRef.current.changeName(this.handleNameUpdate)
 }
// 父组件 使用 ref 调用函数式 - 子组件的方法
chanegSonTest = () => {
  this.childFucRef && this.childFucRef.test()
  const res = this.childFucRef.getTestName() // 通过getTestName 在子组件获取最新的name数据
  console.log('拿到子组件的数据name',res);
 }
 componentDidMount() {}
 render(){
   return (
     <div>
      <Son ref={this.childRef} ></Son>
      <button onClick={this.chanegSonName}>app父组件调用子组件方法</button>
      <div>--------分割线------</div>
      <SonFuc ref={ref => this.childFucRef = ref} ></SonFuc>
      <button onClick={this.chanegSonTest}>app父组件调用子组件方法</button>
     </div>
   )
 }
}

son.jsx 子组件
import React, { Component } from 'react';

export default class son extends Component {
 state = {
  name :'我是son的name'
 }
 changeName = (cb) => {
  let { name } = this.state
  name = name + "1"
  this.setState({ name }, () => {
    cb(this.state.name);
  });
 }
 componentDidMount() {}
 render(){
  let { name } = this.state
   return (
     <div>son
      name - {name}
     </div>
   )
 }
}

效果

在这里插入图片描述

函数组件

app.jsx
import React, { Component } from 'react';
import SonFuc from "./fucSon";
import Son from "./son";
export default class app1 extends Component {
// childRef = null
childRef =  React.createRef()
childFucRef = null
handleNameUpdate = (updatedName) => {
  console.log('updatedName',updatedName);
}
// 父组件 使用 ref 调用类组件 - 子组件的方法 通过cb回调函数拿到当前最新的子组件的数据
chanegSonName = () => {
  this.childRef.current && this.childRef.current.changeName(this.handleNameUpdate)
 }
// 父组件 使用 ref 调用函数式 - 子组件的方法
chanegSonTest = () => {
  this.childFucRef && this.childFucRef.test()
  const res = this.childFucRef.getTestName() // 通过getTestName 在子组件获取最新的name数据
  console.log('拿到子组件的数据name',res);
 }
 componentDidMount() {}
 render(){
   return (
     <div>
      <Son ref={this.childRef} ></Son>
      <button onClick={this.chanegSonName}>app父组件调用子组件方法</button>
      <div>--------分割线------</div>
      <SonFuc ref={ref => this.childFucRef = ref} ></SonFuc>
      <button onClick={this.chanegSonTest}>app父组件调用子组件方法</button>
     </div>
   )
 }
}

fucSon.jsx 子组件
import React, { forwardRef, useImperativeHandle, useState } from 'react';

const FucSonRef = forwardRef((props, ref) => {
  // console.log(props)
  let [testname,setName] = useState('testname')
  // 函数式组件 使用 useImperativeHandle 抛出方法
  useImperativeHandle(ref, () => ({
    test,
    testname,
    getTestName
  }));
  const test = () => {
    testname = testname + "1"
    setName(testname)
  }
  const getTestName = ()=>{
    return testname
  }
  return (
    <div>
      funcson组件 - testname {testname}
    </div>
  )
})

export default FucSonRef;

效果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值