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;
}
相关推荐
kyriewen1 分钟前
一口气讲清楚 Monorepo、Turborepo、pnpm、Changesets 到底是什么?
前端·架构·前端工程化
logo_2821 分钟前
Xpath语法规则的学习和使用
javascript·python·xpath·xpath语法
IT_陈寒1 小时前
React性能优化踩的坑,这个错你可能也会犯
前端·人工智能·后端
zhangxingchao1 小时前
AI应用开发三:RAG技术与应用
前端·人工智能·后端
摘星小杨1 小时前
如何在前端循环调取接口,实时查询数据
开发语言·前端·javascript
Hilaku2 小时前
从搜索排名到 AI 回答? 先聊一聊 AI 可见度工具 BuildSOM !
前端·javascript·程序员
zzmgc42 小时前
纯静态 + Web Worker + 虚拟滚动:我是怎么让浏览器吃下 10MB JSON 不卡的
前端·架构
辰同学ovo2 小时前
用 Chrome DevTools MCP 给 AI 写的页面做“质检“
前端·人工智能·chrome devtools
乌托邦2 小时前
uni-mini-ci:让 uniapp 小程序构建后自动预览和上传
前端·vue.js·uni-app
豹哥学前端2 小时前
前端工程化实战:从包管理到 Vite 配置,一套下来全明白
前端·javascript·vite