Typescript和React造轮子一之React hook基础(二)


第一个简单组件hello word

import React, { useContext } from 'react'
import { ThemeContext } from '../App'
interface IHelloProps {
  message?: string;
}

const Hello: React.FC<IHelloProps> = (props) => {
  const theme = useContext(ThemeContext)
  console.log(theme)
  const style = {
    background: theme.background,
    color: theme.color,
  }
  return <h2 style={style}>{props.message}</h2>
}
Hello.defaultProps = {
  message: "Hello World"
}

export default Hello
1、hook

钩子是允许从功能组件(function component)“挂钩”React状态和生命周期功能的功能。钩子在类内部不起作用 - 它们允许你在没有类的情况下使用React。

useState简单实例

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
1-1、useEffect

Effect Hook中的useEffect增加了在功能组件执行副作用的功能。它与React类中的componentDidMount,componentDidUpdate和componentWillUnmount具有相同的用途,但统一为单个API。
简单实例:

import React, { useState, useEffect } from 'react'

const MouseTracker: React.FC = () => {
  const [ positions, setPositions ] = useState({x: 0, y: 0})
  useEffect(() => {
    console.log('add effect', positions.x)
    const updateMouse= (e: MouseEvent) => {
      console.log('inner')
      setPositions({ x: e.clientX, y: e.clientY })
    }
    document.addEventListener('click', updateMouse)
    return () => {
      console.log('remove effect', positions.x)
      document.removeEventListener('click', updateMouse)
    }
  }, [])
  console.log('before render', positions.x)
  return (
    <p>X: {positions.x}, Y : {positions.y}</p>
  )
}

export default MouseTracker

useEffect不过不传递第二个参数在页面每次重新渲染时都会调用,这里第二个参数传入空数组的意思是只有在页面出现或者卸载时执行.如果传入其他变量则执行与否只依赖该变量是否变化.

不同组件之间共享hook封装

import React, { useState, useEffect } from 'react'

const useMousePosition = () => {
  const [ positions, setPositions ] = useState({x: 0, y: 0})
  useEffect(() => {
    console.log('add effect', positions.x)
    const updateMouse= (e: MouseEvent) => {
      setPositions({ x: e.clientX, y: e.clientY })
    }
    document.addEventListener('mousemove', updateMouse)
    return () => {
      console.log('remove effect', positions.x)
      document.removeEventListener('mousemove', updateMouse)
    }
  }, [])
  return positions
}

export default useMousePosition

定义后在其他组件中引入就可共用状态

const positons = useMousePosition();

自定义hook
在react hook中我们可以把一些天然逻辑重复的业务抽离出来,下面看下例子:
定义文件useURLLoader.tsx

import { useState, useEffect } from 'react'
import axios from 'axios'

const useURLLoader = (url: string, deps: any[] = []) => {
  const [data, setData] = useState<any>(null)
  const [loading, setLoading] = useState(false)
  useEffect(() => {
    setLoading(true)
    axios.get(url).then(result => {
      setData(result.data)
      setLoading(false)
    })
  }, deps)
  return [data, loading]
}

export default useURLLoader

使用

interface IShowResult {
  message: string;
  status: string;
}

const App: React.FC = () => {
     const [show, setShow] = userState(true)
     const [data, loadin] = userState(true) = useURLLoader('https://dog.ceo/api/breeds/imagte', show)
     const dogResult = data as IShowResult 
    return (
        <div>
          <button oClick={() => {
           setShow(!show)
        }}>
           Refresh dog photo
          </button>
              
          {loading ? <p>读取中</p> : <imag src={dogResult && dogResult.message}  />}
        </div>
    )
}
1-2、useRef与useContext

在这里插入图片描述
在这里插入图片描述

App.tsx文件

import React, { useState } from 'react';
import './App.css';
import LikeButton from './components/LikeButton'

interface IThemeProps {
  [key: string]: {color: string; background: string;}
}
const themes: IThemeProps = {
 'light': {
   color: '#000',
   background: '#eee',
 },
 'dark': {
    color: '#fff',
    background: '#222',
  }
}
export const ThemeContext = React.createContext(themes.light)
const App: React.FC = () => {
  const [ show, setShow ] = useState(true)
  return (
    <div className="App">
      <ThemeContext.Provider value={themes.dark}>
      <header className="App-header">
        <LikeButton />
      </header>
      </ThemeContext.Provider>
    </div>
  );
}

export default App;

LikeButton.tsx文件

import React, { useState, useEffect, useRef, useContext } from 'react'
import { ThemeContext } from '../App'
const LikeButton: React.FC = () => {
  const [like, setLike] = useState(0)
  const likeRef = useRef(0)
  const didMountRef = useRef(false)
  const domRef = useRef<HTMLInputElement>(null)
  const theme = useContext(ThemeContext)
  console.log(theme)
  const style = {
    background: theme.background,
    color: theme.color,
  }
  useEffect(() => {
    console.log('document title effect is running')
    document.title = `点击了${like}次`
  }, [like])
  useEffect(() => {
    if (didMountRef.current) {
      console.log('this is updated')
    } else {
      didMountRef.current = true
    }
  })
  useEffect(() => {
    if (domRef && domRef.current) {
      domRef.current.focus()
    }
  })
  function handleAlertClick() {
    setTimeout(() => {
      alert('you clicked on ' + likeRef.current)
    }, 3000)
  }
  return (
    <>
    <input type="text" ref={domRef} />
    <button style={style} onClick={() => {setLike(like + 1); likeRef.current++}}>
      {like} 👍
    </button>
    <button onClick={handleAlertClick}> Alert!
    </button>
    </>
  )
}
export default LikeButton
1-3、 forwardRef

引用传递(Ref forwading)是一种通过组件向子组件自动传递 引用ref 的技术。

import React, { Component, createRef, forwardRef } from 'react';

const FocusInput = forwardRef((props, ref) => (
    <input type="text" ref={ref} />
));

class ForwardRef extends Component {
    constructor(props) {
        super(props);
        this.ref = createRef();
    }

    componentDidMount() {
        const { current } = this.ref;
        current.focus();
    }

    render() {
        return (
            <div>
                <p>forward ref</p>
                <FocusInput ref={this.ref} />
            </div>
        );
    }
}
export default ForwardRef;

1-4、useRef
const refContainer = useRef(initialValue);

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。

一个常见的用例便是命令式地访问子组件:

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

useRef和createRef的区别
react中useState、useRef、变量之间的区别

1-5、useRequest
import { useRequest } from '@umijs/hooks';

function getUsername() {
  return Promise.resolve('jack');
}

export default () => {
  const { data, error, loading } = useRequest(getUsername)
  
  if (error) return <div>failed to load</div>
  if (loading) return <div>loading...</div>
  return <div>Username: {data}</div>
}


这是一个最简单的网络请求示例。在这个例子中 useRequest 接收了一个 Promise 函数。在组件初始化时,会自动触发 getUsername 执行,并自动管理 data 、 loading 、 error 等数据,我们只需要根据状态来写相应的 UI 实现即可。
useRequest教程

1-6、useCreation

1、确定输入输出,useCreation接受两个参数,一个工厂函数,一个依赖项数组,并返回工厂函数执行后的结果
在这里插入图片描述

1-7、useMemo和 useCallback

一篇文章带你理解 React 中最“臭名昭著”的 useMemo 和 useCallback

2、组件之间的传值

参考
父组件

import { useCallback, useEffect, useState, useRef } from "react";
import Header from "../../components/header/index";
import Footer from "../../components/footer/index";
import Changefather from "./components/changefather";

const Home = () => {
  const [sisters, setsisters] = useState("村里一朵花");
  const [loding, setloding] = useState(false); //loding;
  const [childData, setChildData]: any = useState(); //获取子组件的值
  const childMethodRef:any = useRef();
  const changeloding = () => {
    setloding(true);
    setTimeout(() => {
      setloding(false);
    }, 1000);
  };
  const handleChildFun = () => {
    childMethodRef.current.fun2()
  };
  const getchildfn = useCallback((data: any) => {
    setChildData(data);
  }, []);
  return (
    <div className="home">
      <div className="home_div">
        <Header headeractive={1}></Header>
        <Changefather
          sisters={sisters}
          setsisters={setsisters}
          handleChildData={getchildfn}
          cRef={childMethodRef}
        ></Changefather>
        <div className="buttondiv">
          <span>这是一个小小的button</span>
          <div className="lodingdiv" style={loding ? {} : { display: "none" }}>
            <div className="loding"></div>
          </div>
        </div>
        <button
          onClick={() => {
            changeloding();
          }}
        >
          changeloding
        </button>
        {<div>这是子组件的值{childData}</div>}
        <input type="number" placeholder="555" />
      </div>
      <div
        onClick={() => {
          handleChildFun();
        }}
      >
        我要
      </div>
      <Footer></Footer>
    </div>
  );
};
export default Home;



子组件

import{ useEffect, useState ,useImperativeHandle,forwardRef} from "react";
import Countdown from "react-countdown";
import dayjs from "dayjs";

interface sister {
  sisters: string;
  setsisters: any;
  handleChildData:any;
  cRef:any
}
let Changeyears = (props: sister):any => {
  const { sisters, setsisters,handleChildData,cRef } = props;
  const [Cdtime,setCdtime]=useState(dayjs(1649999957832).valueOf())
  const [childtext , setchildtext ] = useState('')
  useImperativeHandle(cRef, () => ({
    childFun (info: any) {
    console.log(info)
    },
    fun2(){
    console.log('fun2')
    }
    }));
  useEffect(()=>{
    handleChildData(childtext)
  },[childtext])
  return (
    <>
      <Countdown date={Cdtime} 
       renderer={time => {
         const {days,hours,minutes,seconds} = time.formatted
         return (
           <div>
             还有{days}天{hours}时{minutes}分{seconds}秒
           </div>
         )
       }}
      />
      <div onClick={()=>{
        setchildtext('今天给爸爸洗脚')
      }}>传给父组件值</div>
      <div onClick={()=>{
        setchildtext('今天不给爸爸洗脚')
      }}> 第二次传给父组件的值</div>
      <div className="animate__flash">{sisters}</div>
      <button onClick={() => setsisters("老太婆")}>时间的变迁</button>
    </>
  );
};

Changeyears = forwardRef(Changeyears);

export default Changeyears;



请添加图片描述

import React, { useRef, useImperativeHandle } from 'react';
import ReactDOM from 'react-dom';

const FancyInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} type="text" />
});

const App = props => {
  const fancyInputRef = useRef();

  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button
        onClick={() => fancyInputRef.current.focus()}
      >父组件调用子组件的 focus</button>
    </div>
  )
}

ReactDOM.render(<App />, root);


3、自定义hook实现
import React,{Component,useState} from 'react'

function useCountFather(initValue){
  var [count,setCount]=useState(initValue)
  function increase(){
    setCount(++count)
  }
  function decrease(){
    setCount(--count)
  }
  return [count,{increase,decrease}]
}

function Count(){
  var [count,countFatherApi]=useCountFather(0)
  
  return(
    <div>
      <p>{count}</p>
      <button onClick={()=>{countFatherApi.increase()}}>Increase</button>
      <button onClick={()=>{countFatherApi.decrease()}}>Decrease</button>
    </div>
  )
}

function App(){
  return(
    <div>
      <Count></Count>
    </div>
  )
}

export default App;



4、hook中网络请求数据
import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
  const [data, setData] = useState({ hits: [] });
 
  useEffect(async () => {
    const result = await axios(
      'https://hn.algolia.com/api/v1/search?query=redux',
    );
 
    setData(result.data);
  });
 
  return (
    <ul>
      {data.hits.map(item => (
        <li key={item.objectID}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}
 
export default App;


手动触发

function App() {
  const [data, setData] = useState({ hits: [] });
  const [query, setQuery] = useState('redux');
  const [search, setSearch] = useState('');
 
  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(
        `http://hn.algolia.com/api/v1/search?query=${query}`,
      );
 
      setData(result.data);
    };
 
    fetchData();
  }, [query]);
 
  return (
    <Fragment>
      <input
        type="text"
        value={query}
        onChange={event => setQuery(event.target.value)}
      />
      <button type="button" onClick={() => setSearch(query)}>
        Search
      </button>
 
      <ul>
        {data.hits.map(item => (
          <li key={item.objectID}>
            <a href={item.url}>{item.title}</a>
          </li>
        ))}
      </ul>
    </Fragment>
  );
}


参考

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
React HookReact 16.8版本引入的一种新的特性,它可以让你在无需编写类组件的情况下使用状态和其他React特性。TypeScript是一种静态类型检查的JavaScript超集,可以帮助我们在开发过程中发现并修复潜在的错误。 要深入学习React HookTypeScript技术栈,你可以按照以下步骤进行: 1. 学习React基础知识:在学习React Hook之前,确保你对React基础知识有一定的了解。理解React组件、生命周期、状态管理等概念是很重要的。 2. 学习TypeScript基础知识:如果你还不熟悉TypeScript,可以先学习一些基础知识,比如类型注解、接口、泛型等。掌握这些概念可以帮助你更好地使用TypeScript进行开发。 3. 学习React Hook:阅读React官方文档中关于React Hook的内容,并尝试编写一些简单的Hook。掌握useState、useEffect、useContext等常用的Hook函数,并理解它们的使用方法和原理。 4. 使用TypeScript编写React Hook:在掌握了React Hook的基本知识后,你可以开始使用TypeScript编写React Hook。使用TypeScript可以为你的代码提供类型检查和智能提示,减少潜在的错误。 5. 实践项目:选择一个小型的项目或者练习,使用React HookTypeScript进行开发。通过实践项目可以帮助你更好地理解和掌握这两个技术栈。 6. 深入学习进阶内容:一旦你对React HookTypeScript有了基本的了解,你可以进一步学习一些进阶内容,比如自定义Hook、使用第三方库、使用Context API等。 记住,深入学习任何技术栈都需要时间和实践。通过不断地阅读文档、编写代码和解决问题,你会逐渐掌握React HookTypeScript技术栈。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值