semi-xi / blog

blog
4 stars 1 forks source link

react hook #33

Open semi-xi opened 3 years ago

semi-xi commented 3 years ago

useCallback 读取一个经常变化的值

利用useRef的不变性,把经常变化的值传入current,在useCallback中读取到这个ref的current值

const [text, setText] = useState('');
const textRef = useRef();

useEffect(() => {
  textRef.current=text;
}, [text]);

const handle = useCallback(() => {
  const currentText = textRef.current;
  alert(currentText);
}, [textRef]);

hook的使用需要在最顶层

不能在循环,条件,或者嵌套函数中调用hook,这让react能够在多次的useState和useEffect调用之间保持hook状态的正确 因为hook靠的是调用顺序来保证state,useState之类的对应, 由于循环或者条件的改变,会导致调用顺序发生变化,从而导致react无法知道hook应该返回什么内容

const states: any[] = [];

let cursor: number;

function useState<T>(initialState: T): [T, (newState: T) => void] {
  const currenCursor = cursor;
  states[currenCursor] = states[currenCursor] || initialState; // 检查是否渲染过

  function setState(newState: T) {
    states[currenCursor] = newState;
    render();
  }

  ++cursor; // update: cursor
  return [states[currenCursor], setState];
}

数据的顺序的改变会导致获取的值异常

可以看下这个无意识设计-复盘React Hook的创造过程

hook使用setInterval异常

错误写法

function Index() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, []);

  return <div>{count}</div>;
}

hook内部实现是一个闭包,这样就会导致获取count永远是0,页面显示的count永远是1

简单解决

useState如果传入一个函数的话,就可以获取到最新的count

但是对于props的话这个就是无效的了

复杂场景

useEffect(() => {
    const timer = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, [count]);

这样的场景越来越多会导致依赖越写越多,如果少写了的话可能会造成很大的影响。

依赖较多的场景

const ref = useRef();

useEffect(() => {
  ref.current = () => {
    setCout(count+1)
  }
})

useEffect(() => {
  const cb = () => {
    ref.current();
  }
  const timer = setInterval(cb, 3000)
  return () => clearInterval(timer);
},[])

逻辑复杂的场景

const reducer = (state, action) {
  return {count: state.count + 1};
}

const [state, dispatch] = useReducer(reducer, {count: 0});

useEffect(() => {
  setInterval(() => {
    dispatch();
  }, 10000)
}, [])

## 避免层层向下传递回调

可以利用useReducer, 把dispath 放在context传递下去,这样可以在任意一个子组件获取之后都可以dispath更新操作

const TodoDispatch = React.createContext(null);

function TodosApp () { const [todos, dispatch] = useReducer(todosReducer);

return

</TodosDispatch.Provider> }