vite4加react18加ts-hooks学习篇

vite4加react18加ts-安装篇; 最近从vue3转型学习了,react相关技术架构,去有意识的去学习了相关东西,内容比较实用,没有引入太多原理和概念,就是最直接最实用的记录下来;

react项目中版本
"react": "^18.2.0",
"react-dom": "^18.2.0",
useState使用指南
  • useState接受一个参数,返回了一个数组;
// 直接更新useState
function App(){
	const [count, setCount] = useState(0);
  // 定义方法
  const increase = () => setCount(count + 1);
  return (
  	<div>
      <span>Count: {count}</span>
      <button onClick={increase}>Add +1</button>
    </div>
  );
}
  • 更新特定对象属性
import { useState, useEffect } from "react";
export default function App() {
  const [user, setUser] = useState({
    name: "Yyh",
    age: 26,
  });
  // 更新用户状态属性
  const changeName = () => {
    setUser((user) => Object.assign({}, user, { name: "King" }));
    // 使用扩展符
    setUser((user) => ({ ...user, name: "King" }));
  };
  // 渲染 UI
  return (
    <div className='App'>
      <p>User: {user.name}</p>
      <p>Age: {user.age}</p>
      <button onClick={changeName}>Change name</button>
    </div>
  );
}
useReducer
  • useReducer 是 useState 的替代方案
/*
reducer: reducer函数。
initialArg: 初始化的state
*/
const initialState = {count: 0};
const reducer = (state, action) => {
	switch(action.type) {
  	case 'increment':
    return {count: state.count + 1};
  	case 'decrement':
    	return {count: state.count - 1};
    default:
    	break;
  }
};
function App() {
	const [state, dispatch] = useReducer(reducer, initialState);
	return (
  	<button onClick={dispatch({type: 'increment'})}>+</buton>
    <button onClick={dispatch({type: 'decrement'})}>-</button>
  )
}
useEffect使用指南

副作用是函数式编程里的概念,在函数式编程的教材中,如下的行为是称之为副作用的

  • 修改一个变量
  • 修改一个对象的字段值
  • 抛出异常
  • 在控制台显示信息、从控制台接收输入
  • 在屏幕上显示(GUI)
  • 读写文件、网络、数据库
/*useEffect(fn, [])接收两个参数 一个是回调函数 另外一个是数组类型的参数*/
// 模拟 componentDidMount
useEffect(() => {
  return () => {};
}, []);
// 模拟componentDidUpdate
useEffect(() => {});
// 监听单个或多个state
useEffect(() => {}, [user, list]);
// 利用匿名函数写async
useEffect(() => {
	(async() => {
  	const userInfo = await getUserInfo();
  })();
});
监听某个state
const [items, setItems] = useState(['A', 'B', 'C']);

useEffect(() => {
     console.log({ items })
}, [items])

const splice = (index) =>{
	// 这种useEffect是不会执行, items是改变了
	let _items = items;
	_items.splice(index,1);
	setItems(_items);
  
  // 解决方案 1.深度拷贝
  let _items = JSON.parse(JSON.stringify(items));
  // 解决方案 2.ES6 ...
  setItems([..._items]);
  // 解决方案 3.slice
  setItems(items.slise(1));
}
监听props
export default (props) => {
	const {data = [] } = props
  useEffect(() => {
    console.log(1);
  }, [data]);
};
createContext和useContext

createContext

  • createContext创建一条索引,相当于开辟了一个空间,可以配置默认参数,支持任何类型
  • Provider提供数据共享,传参使用value,且value固定写法默认,必填,写其他不生效,
    value接收的变量建议state中:每一次 Provider 重渲染时,consumers 组件将会重新渲染,因为value属性总被赋予新值
  • Consumer接收者,必须以函数方式获取
const SecondContext  = createContext();
// 父
import React, { createContext } from "react";
const {count, setCount} = useState(0);
const data = {count, setCount};
return (
	<SecondContext.Provider value={data}>
  	<Children></Children>
  </SecondContext.Provider>
)
// 子
import React, { useContext } from "react";
const {count, setCount} = useContext(SecondContext);
useRef
import {useRef} from "react";
const inputEl: HTMLInputElement = useRef(null);
const handleClick = () => {
	inputEl.current.focus();
};
return(
<>
  <input ref={} type="text" />
  <button onClick={handleClick}>Focus the input</button>
<>
);
什么时候使用useCallback和useMemo
  • 保持引用相等
  • 昂贵的计算

useCallback

react中Class的性能: 在hooks诞生之前,如果组件包含内部state,我们都是基于class的形式来创建组件。react中,性能的优化点在于:

  • 调用setState,就会触发组件的重新渲染,无论前后的state是否不同
  • 父组件更新,子组件也会自动的更新

基于上面的两点,我们通常的解决方案是:

  • 使用immutable进行比较,在不相等的时候调用setState
  • 在shouldComponentUpdate中判断前后的props和state,如果没有变化,则返回false来阻止更新

在hooks出来之后: 我们能够使用function的形式来创建包含内部state的组件。但是,使用function的形式,失去了上面的shouldComponentUpdate,我们无法通过判断前后状态来决定是否更新。而且,在函数组件中,react不再区分mount和update两个状态,这意味着函数组件的每一次调用都会执行其内部的所有逻辑,那么会带来较大的性能损耗。因此useMemo 和useCallback就是用来优化性能问题;

useCallback会返回一个函数的memoized值;

无依赖时,执行原来的函数;依赖项改变时,函数进行一个更新,在依赖不变的情况下,多次定义的时候,返回的值是相同的

// 根据依赖项决定是否更新回调函数fn
const memoizedCallback = useCallback(fn, deps);
const memoizedCallback = useCallback(() => {}, [a, b]);

/* 场景:有一个父组件,其中包含子组件,子组件接收一个函数作为props;
通常而言,如果父组件更新了,子组件也会执行更新;但是大多数场景下,
更新是没有必要的,我们可以借助useCallback来返回函数,
然后把这个函数作为props传递给子组件;这样,子组件就能避免不必要的更新。*/
// 场景:将父组件的函数,传给子组件作为回调使用时
import React, { memo,  useCallback} from "react";
// 父组件
export default Parent = () => {
	const [count, setCount] = useState(1);
  const [val, setVal] = useState('');
  const callback = useCallback(() => {
  	return count;
  }, [count]);
  return (
  	<div>
    	<Child callback={callback}/>
      <button onClikc={setCount(count + 1)}></button>
      <button onClikc={setVal(val + 1)}></button>
    </div>
  );
};
// 子组件
const Child = ({ callback } => {
	const [count, setCount] = useState();
  useEffect(() => {
  	setCount(callback());
  }, [callback]);
  return (<div>{count}</div>)
});
export default React.memo(Child);
useMemo

和useCallback类似,区别就是useCallback返回一个 memoized函数,而useMemo返回一个memoized 值;
优化针对于当前组件高开销的计算,具有记忆功能假如页面上有一个比较大的高开销的计算,每次set一个值的时候,都会重新执行计算函数,这样的话,很占内存

/* useMemo可以用来做缓存计算属性的 */
export default const Com = () => {
	const [count, setCount] = useState(1);
  const unit = useMomo(() => {
  	return count * 7;
  }, count);
	return (
  	<div onClick={setCount(count + 1)}>美元:${unit}count: {}</div>
  )
};
/*useMemo 优化子组件props渲染*/
// useMemo是一个React Hook 确保该函数中的值仅在其依赖项之一发生变化时才重新计算
export default const Parent = () => {
	const [count, setCount] = useState(1);
	const childRelyOn = useMomo(() => {}, [count])
  return (
  	<div><Children childRelyOn= {childRelyOn}/></div>
  )
}
export default const Childre = ({childRelyOn}) => {
	return (<div>childRelyOn</div>)
}
/*React.memo使用*/
// React.memo()是一个高阶组件,除非其中的 props 发生变化才会渲染
import React, { useMomo } from 'react';
const Child = React.memo(function Children(props) {
	return (
  	<>
      <div onClick={props.clickHandle}>{props.count}</div>
    </>
  )
}, (preProps, nextProps) => {
	return JSON.stringify(preProps) === JSON.stringify(nextProps);
}); 
// 第二个参数也可以不传
React.memo(function Children(props) {});
props默认值+slot
import React, { ReactNode } from 'react';
import style from './style.module.less';
interface PropsType {
    children: ReactNode;
    position?: 'fixed';
}
// 指定默认值
DragSlot.defaultProps = {
    position: 'fixed'
}
export default function DragSlot(props: PropsType) {
    return (<div className={`${props.clasName} ${style.root}`}
        style={{position: `${props.position ? props.position : 'fixed'}`}}>
    </div>)
}
// 使用
<DragSlot>
    <div>hello yyh</div>
</DragSlot>
props类型校验
import PropTypes from 'prop-types';
DragSlot.propTypes = {
   name: PropTypes.string.isRequired,
   age: PropTypes.number
}
子组件调用父组件方法
// 父组件
export default Father = () => {
	let getInfo() = () => {};
  return (
  	<>
    	<Children getInfo={getInfo}
    <>
  )
};
// 子组件
export default Children = (props) => {
	return (
  	<div onClick={props.getInfo}></div>
  );
};
父组件调用子组件方法
// 父
import React, { useRef } from 'react';
export default function Parant() {
	const childRef = useRef();
  return (
  	<div>
    	<Child ref={childRef}/>
      <button onClick={() => {childRef.current.focus()}}>聚焦</button>
      <button onClick={() => {childRef.current.handleSubmit()}}>提交</button>
    </div>
  );
};
// 子用forwardRef包裹子组件,用useImperativeHandle定义方法
import React, { useRef, forwardRef, useImperativeHandle } from 'react';
export default child = forwardRef((props, ref) => {
	const inputRef = useRef();
	const handleSubmit = () => {}
	useImperativeHandle(ref, () => {
  	focus: () => {
      inputRef.current.focus()
    },
    handleSubmit,
  });
  return (
  	<div><input tepe="text" ref={inputRef}/></div>
  );
});
插槽solt实现
// props方式
export default function NavBar({leftSlot, centerSlot, rightSlot}) {
};
<NavBar
	leftSlot={<div>leftSlot</div>}
	centerSlot={<div>centerSlot</div>}
  rightSlot={<div>rightSlot</div>}>
</NavBar>
// 嵌套方式 
export default function MyForm({children}) {
	return (<>{children}</>);
};

你可能感兴趣的:(react,typescript,javascript,前端)