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;
}
相关推荐
陪我一起学编程31 分钟前
创建Vue项目的不同方式及项目规范化配置
前端·javascript·vue.js·git·elementui·axios·企业规范
LinXunFeng1 小时前
Flutter - 详情页初始锚点与优化
前端·flutter·开源
GISer_Jing1 小时前
Vue Teleport 原理解析与React Portal、 Fragment 组件
前端·vue.js·react.js
Summer不秃1 小时前
uniapp 手写签名组件开发全攻略
前端·javascript·vue.js·微信小程序·小程序·html
coderklaus2 小时前
Base64编码详解
前端·javascript
NobodyDJ2 小时前
Vue3 响应式大对比:ref vs reactive,到底该怎么选?
前端·vue.js·面试
xianxin_2 小时前
CSS Visibility(可见性)
前端
朱程2 小时前
写给自己的 LangChain 开发教程(二):格式化数据 & 提取 & 分类
前端·人工智能
小喷友2 小时前
第5章 高级UI与动画
前端·app·harmonyos
笃行3502 小时前
【实用部署教程】olmOCR智能PDF文本提取系统:从安装到可视化界面实现
前端