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
    评论
React 函数组件中,获取 DOM 节点的方式与在组件中有所不同,因为函数组件没有实例化对象,因此无法使用 ref 属性来获取 DOM 节点。 通常情况下,React 鼓励开发者遵循“单向数据流”的原则,即通过 props 和 state 来管理组件的状态和数据,而不是直接操作 DOM 节点。因此,如果想要获取 DOM 节点,应该考虑使用 React 提供的 ref 回调函数或者 Hook。 1. 使用 ref 回调函数 可以通过 ref 回调函数获取 DOM 节点,并将其保存在组件的 state 中。具体实现方式如下: ```jsx import React, { useState, useRef } from 'react'; function MyComponent() { const [domNode, setDomNode] = useState(null); const handleClick = () => { console.log(domNode); }; return ( <div ref={node => setDomNode(node)}> <button onClick={handleClick}>Click me</button> </div> ); } ``` 上面的代码中,我们使用 useState Hook 来定义一个 state 变量 domNode,然后在组件JSX 中使用 ref 属性来获取 DOM 节点,并将其传递给一个回调函数,这个回调函数会将当前的 DOM 节点作为参数,然后将它保存在 domNode 变量中。最后,我们可以在 handleClick 函数中打印 domNode 变量来获取 DOM 节点。 2. 使用 useRef Hook 另一种获取 DOM 节点的方式是使用 useRef Hook。useRef Hook 可以返回一个可变的 ref 对象,它的 current 属性可以存储任意值。具体实现方式如下: ```jsx import React, { useRef } from 'react'; function MyComponent() { const domNode = useRef(null); const handleClick = () => { console.log(domNode.current); }; return ( <div ref={domNode}> <button onClick={handleClick}>Click me</button> </div> ); } ``` 上面的代码中,我们使用 useRef Hook 来定义一个 ref 对象 domNode,然后在组件JSX 中使用 ref 属性将其绑定到一个 DOM 节点上。最后,我们可以在 handleClick 函数中打印 domNode.current 属性来获取 DOM 节点。 总的来说,虽然在函数组件获取 DOM 节点比在组件中麻烦一些,但是通过使用 ref 回调函数或者 Hook,我们仍然可以轻松地获取到需要的 DOM 节点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值