vite4加react18加ts-安装篇; 最近从vue3转型学习了,react相关技术架构,去有意识的去学习了相关东西,内容比较实用,没有引入太多原理和概念,就是最直接最实用的记录下来;
"react": "^18.2.0",
"react-dom": "^18.2.0",
// 直接更新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>
);
}
/*
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(fn, [])接收两个参数 一个是回调函数 另外一个是数组类型的参数*/
// 模拟 componentDidMount
useEffect(() => {
return () => {};
}, []);
// 模拟componentDidUpdate
useEffect(() => {});
// 监听单个或多个state
useEffect(() => {}, [user, list]);
// 利用匿名函数写async
useEffect(() => {
(async() => {
const userInfo = await getUserInfo();
})();
});
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));
}
export default (props) => {
const {data = [] } = props
useEffect(() => {
console.log(1);
}, [data]);
};
createContext
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);
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
react中Class的性能: 在hooks诞生之前,如果组件包含内部state,我们都是基于class的形式来创建组件。react中,性能的优化点在于:
基于上面的两点,我们通常的解决方案是:
在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);
和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) {});
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>
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>
);
});
// 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}</>);
};