1. useState
1.1 useState的用法,以及简单实现
import React from 'react';
import ReactDOM from 'react-dom';
let hookStates = [];
let hookIndex = 0;
function useState(initialState) {
if (typeof initialState === 'function') {
hookStates[hookIndex] = hookStates[hookIndex] || initialState();
} else {
hookStates[hookIndex] = hookStates[hookIndex] || initialState;
}
let currentIndex = hookIndex;
function setState(newState) {
if (typeof newState === 'function') {
newState = newState(hookStates[currentIndex])
}
hookStates[currentIndex] = newState;
render();
}
return [hookStates[hookIndex++], setState]
}
function App() {
const [{number}, setNumber] = useState(() => ({number: 0}));
const [name, setName] = useState('jeffywin');
return (
<>
<p>{number}</p>
<p>{name}</p>
<button onClick={() => setNumber({number: number + 1})}>+</button>
<button onClick={() => setName(name + 's')}>changeName</button>
</>
);
}
function render() {
hookIndex = 0;
ReactDOM.render(
<App />,
document.getElementById('root')
);
}
render();
2. uesRef
2.1 useRef的用法
- useRef一般用在获取最新的值,以及操作dom元素
- useRef会返回一个可变的ref对象 {current}
- ref对象在组件的整个生命周期内保持不变
function Counter(){
let [number,setNumber] = useState(0);
let lastNumberRef = useRef(number);
let alertNumber = ()=>{
setTimeout(() => {
alert(lastNumberRef.current);
}, 3000);
}
React.useEffect(()=>{
lastNumberRef.current = number;
});
return (
<div>
<p>{number}</p>
<button onClick={()=>{
setNumber(number+1);
}}>+</button>
<button onClick={alertNumber}>alert</button>
</div>
)
}
function render(){
hookIndex = 0;
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
}
render();
2.2 useRef的实现
- useRef的实现比较简单,直接把current传过去
function useRef(current) {
hookStates[hookIndex] = hookStates[hookIndex]||{current}
return hookStates[hookIndex++]
}
2.3 forwardRef是什么,为什么需要,怎么实现
- forwardRef 将ref从父组件转发到子组件的dom元素上,子组件接收props和ref
- 为什么需要forwardRef,因为函数组件没有实例,父无法直接给子传 ref,而类组件是可以直接传的
- 通过给子组件包装forwardRef, React.forwardRef(FunctionChild) 就可以达到传递ref的目的
- forwardRef怎么用, 例子,获取input焦点
function FunctionChild(props, ref) {
return <input ref={ref} />;
}
class ClassChild extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
render() {
return <input ref={this.inputRef} />;
}
}
const ForwardFunctionChild = React.forwardRef(FunctionChild);
function Parent() {
let [number, setNumber] = React.useState(0);
const functionChildRef = React.useRef();
const getFocus = () => {
functionChildRef.current.focus();
};
return (
<div>
{/* 把useRef传给经过forwardRef包裹后的子组件 */}
<ForwardFunctionChild ref={functionChildRef} />
<ClassChild ref={classChildRef} />
<p>{number}</p>
<button onClick={() => setNumber((x) => x + 1)}>+</button>
<button onClick={getFocus}>获得焦点</button>
</div>
);
}
function render() {
hookIndex = 0;
ReactDOM.render(<Parent />, document.getElementById("root"));
}
render();
- 简单实现
function forwardRef(FunctionChild){
return class extends React.Component{
render(){
return <FunctionChild {...this.props}/>
}
}
}
2.4.useImperativeHandle是什么,怎么用,以及怎么实现
- functionChildRef.current 这是真实DOM, 如果不做保护,就可以做很多危险的操作
function FunctionChild(props, ref) {
let inputRef = React.useRef();
useImperativeHandle(ref, () => ({
focus() {
inputRef.current.focus();
},
}));
return <input ref={inputRef} />;
}
const ForwardFunctionChild = React.forwardRef(FunctionChild);
function Parent() {
let [number, setNumber] = React.useState(0);
const functionChildRef = React.useRef();
const classChildRef = React.useRef();
const getFocus = () => {
};
return (
<div>
{/* 把ref传给经过forwardRef包裹后的子组件 */}
<ForwardFunctionChild ref={functionChildRef} />
<ClassChild ref={classChildRef} />
<p>{number}</p>
<button onClick={() => setNumber((x) => x + 1)}>+</button>
<button onClick={getFocus}>获得焦点</button>
</div>
);
}
function render() {
hookIndex = 0;
ReactDOM.render(<Parent />, document.getElementById("root"));
}
render();
function useImperativeHandle(ref, factory) {
ref.current = factory();
}