React Hooks UseRef的用法

开发环境时Taro+React Native+TypeScript

TypeScript 复制代码
export interface TimerRef{
  timeShow: ()=>{};
  getCurrentTime: () => number;
}

// 修改这里:添加 props 参数,即使不使用也要保留位置
const Timer = forwardRef<TimerRef, {}>((props, ref) => {
  const [count, setCount] = useState(0);
  const timerRef = useRef<NodeJS.Timeout | null>(null);
  const memoryName = 'Time Pace'

  // 暴露方法给父组件
  useImperativeHandle(ref, ()=>({
    timeShow: ()=>{
      console.log("定时器的当前时间: current time = ", count)
      console.log("memoryName = ", memoryName)
    },
    getCurrentTime: ()=>{
      return count
    }
    
  }))

  const startTimer = () => {
    // 如果已经有定时器在运行,先清除
    if (timerRef.current !== null) {
      clearInterval(timerRef.current);
    }
    timerRef.current = setInterval(() => {
      setCount(prev => prev + 1);
    }, 1000);
  };

  const stopTimer = () => {
    if (timerRef.current !== null) {
      clearInterval(timerRef.current);
      timerRef.current = null; // 清除后重置为 null
    }
  };

  useEffect(() => {
    return () => {
      if (timerRef.current !== null) {
        clearInterval(timerRef.current);
      }
    };
  }, []);

  return (
    <div>
      <p>计数: {count}</p>
      <button className='btn' style={{marginRight: 20}} onClick={startTimer}>开始</button>
      <button className='btn' onClick={stopTimer}>停止</button>
    </div>
  );
})
TypeScript 复制代码
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react'
import { View, Text, Button } from '@tarojs/components'
import './index.scss'

interface IProps{
  color: string;
  size: string;
  originalPrice?: string;
  description?: string;
  likeStar?: string;
  price: number;
}

const DressPaper = (props:IProps) => {

  const [price, setPrice] = useState(props.price)
  const [likeStar, setLikeStar] = useState(props.likeStar || 'star, ')
  const priceRef = useRef<HTMLSpanElement>(null)
  const preStarsNumRef = useRef(0)
  const timeRef = useRef<TimerRef>(null)
  

  // 改变价格
  const changeDressPrice = ()=>{
    setPrice(prePrice =>{
      return ++prePrice 
    });

    // 使用useRef动态改变元素的样式
    if(priceRef.current){
      // const element = priceRef.current as unknown as HTMLElement;
      priceRef.current.style.color = 'blue'
    }
  }

  // 使用ref存储上一次的值
  // 增加like Star并记录上一次增加后的次数
  const addLikeStar = ()=>{
    setLikeStar(preLikeStar => {
      return preLikeStar + 'star, '
    })
    // useRef修饰的值跨越整个生命周期都不会改变,但当值改变时也可以更新在页面中
    preStarsNumRef.current++
  }

  //子组件的事件处理
  const handleSubShow = ()=>{
    console.log("通过ref在子组件中获取的当前时间 current time = ", timeRef.current?.getCurrentTime())
    timeRef.current?.timeShow()
  }

  return (<View>
    <View className='container'>
      <Text ref={priceRef} className='txt'>Price: {'$' + price}</Text>
      <Text className='txt'>{likeStar}</Text>
      <Text className='txt'>上一次增加的star个数为:{preStarsNumRef.current}</Text>
    </View>
    <View>
      <Button className='btn' onClick={changeDressPrice}>change price</Button>
      <Button className='btn' onClick={addLikeStar}>add like star</Button>
    </View>
    <View style={{backgroundColor: '#cc9999'}}>
      <Text className='txt'>
        使用useRef做父子组件间的通信,存储定时器, 组件销毁时清除定时器
      </Text>
      <Timer ref={timeRef}></Timer>
      <Button className='btn' onClick={handleSubShow}>
        父组件调用子组件方法,修改子组件的属性
      </Button>
    </View>
  </View>
  );
}

export default DressPaper;
TypeScript 复制代码
import UseRefComponent from "../Hooks/UseRef";
<UseRefComponent color='blue' size='m' price={20}></UseRefComponent>

下面的是样式scss文件

TypeScript 复制代码
.container {
  display: flex;
  flex-direction: column;
  padding: 20px;
  background-color: #ADD8E6;
  margin-bottom: 40px;
}

.txt {
  height: 44px;
  padding: 15px 100px;
  margin-bottom: 7px;
  background-color: #FFE4E1;
  font-size: 26px;
}

.btn {
  height: 64px;
  // padding: 15px 100px 15px 100px;
  margin-bottom: 7px;
  background-color: #D8BFD8;
  font-size: 28px;
}

.buttonContainer {
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  margin-bottom: 20px;
}

.input {
  background-color: white;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
}
相关推荐
快乐肚皮15 小时前
一文了解XSS攻击:分类、原理与全方位防御方案
java·前端·xss
保护我方头发丶15 小时前
ESP-wifi-蓝牙
前端·javascript·数据库
想学后端的前端工程师15 小时前
【Flutter跨平台开发实战指南:从零到上线-web技术栈】
前端·flutter
老王Bingo15 小时前
Qwen Code + Chrome DevTools MCP,让爬虫、数据采集、自动化测试效率提升 100 倍
前端·爬虫·chrome devtools
董世昌4116 小时前
什么是扩展运算符?有什么使用场景?
开发语言·前端·javascript
Yaru1116 小时前
Vue 3.6 预览版特性
javascript·vue.js
来杯三花豆奶16 小时前
Vue 3.0 Mixins 详解:从基础到迁移的全面指南
前端·javascript·vue.js
想学后端的前端工程师16 小时前
【React性能优化实战指南:从入门到精通-web技术栈】
前端·react.js·性能优化
白兰地空瓶16 小时前
React Hooks 深度理解:useState / useEffect 如何管理副作用与内存
前端·react.js
cike_y17 小时前
JSP内置对象及作用域&双亲委派机制
java·前端·网络安全·jsp·安全开发