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;
}
相关推荐
东风西巷1 小时前
PDFgear:免费全能的PDF处理工具
前端·pdf·软件需求
森之鸟2 小时前
Mac电脑上如何打印出字体图标
前端·javascript·macos
mCell2 小时前
GSAP 入门指南
前端·javascript·动效
gnip3 小时前
组件循环引用依赖问题处理
前端·javascript
Aotman_4 小时前
el-input textarea 禁止输入中文字符,@input特殊字符实时替换,光标位置保持不变
前端·javascript·vue.js·前端框架·es6
Nan_Shu_6144 小时前
Web前端面试题(1)
前端·面试·职场和发展
EveryPossible4 小时前
选择数据展示
javascript
lypzcgf4 小时前
Coze源码分析-资源库-创建知识库-前端源码-核心组件
前端·typescript·react·coze·coze源码分析·ai应用平台·agent开发平台
百思可瑞教育5 小时前
在Vue项目中Axios发起请求时的小知识
前端·javascript·vue.js·北京百思教育
患得患失9495 小时前
【个人项目】【前端实用工具】OpenAPI to TypeScript 转换器
前端·javascript·typescript