如何在React中使用usestate Hook使用回调



我正在使用带有钩子的功能组件。我需要从孩子中更新父母的状态。我在父母中使用道具功能。除了我的道具功能是获得以前的状态,而不是当前状态,所有功能都很好。我的Prop功能在 usestate 挂钩设置当前状态之前被执行。在USESESESTATE呼叫后,我如何等待我的回电函数被执行。我正在寻找基于类的组件的 setState(状态,回调)

这是代码段:

function Parent() {
  const [Name, setName] = useState("");
  getChildChange = getChildChange.bind(this);
  function getChildChange(value) {
    setName(value);
  }
  return <div> {Name} :
    <Child getChildChange={getChildChange} ></Child>
  </div>
}
function Child(props) {
  const [Name, setName] = useState("");
  handleChange = handleChange.bind(this);
  function handleChange(ele) {
    setName(ele.target.value);
    props.getChildChange(collectState());
  }
  function collectState() {
    return Name;
  }
  return (<div>
    <input onChange={handleChange} value={Name}></input>
  </div>);
} 

您可以使用usefect/uselayouteffect实现这一目标:

const SomeComponent = () => {
  const [count, setCount] = React.useState(0)
  React.useEffect(() => {
    if (count > 1) {
      document.title = 'Threshold of over 1 reached.';
    } else {
      document.title = 'No threshold reached.';
    }
  }, [count]);
  return (
    <div>
      <p>{count}</p>
      <button type="button" onClick={() => setCount(count + 1)}>
        Increase
      </button>
    </div>
  );
};

如果要防止回调在第一次渲染时运行,请调整以前的版本:

const SomeComponent = () => {
  const [count, setCount] = React.useState(0)
  const didMount = React.useRef(false);
  React.useEffect(() => {
    if (!didMount.current) {
      didMount.current = true;
      return;
    }
    if (count > 1) {
      document.title = 'Threshold of over 1 reached.';
    } else {
      document.title = 'No threshold reached.';
    }
  }, [count]);
  return (
    <div>
      <p>{count}</p>
      <button type="button" onClick={() => setCount(count + 1)}>
        Increase
      </button>
    </div>
  );
};

在这里有更多关于它的信息。

setState(updater, callback) for useState

实现之后的实现确实接近了类的原始setState回调。

对接受答案的改进:

  1. 初始渲染时省略了回调执行 - 我们只想在State 更新上调用它
  2. 回调可能是每个setState调用的动态,例如类

用法

const App = () => {
  const [state, setState] = useStateCallback(0); // same API as useState
  const handleClick = () => {
    setState(
      prev => prev + 1,
      // second argument is callback, `s` being the *updated* state
      s => console.log("I am called after setState, state:", s)
    );
  };
  return <button onClick={handleClick}>Increment</button>;
}

useStateCallback

function useStateCallback(initialState) {
  const [state, setState] = useState(initialState);
  const cbRef = useRef(null); // init mutable ref container for callbacks
  const setStateCallback = useCallback((state, cb) => {
    cbRef.current = cb; // store current, passed callback in ref
    setState(state);
  }, []); // keep object reference stable, exactly like `useState`
  useEffect(() => {
    // cb.current is `null` on initial render, 
    // so we only invoke callback on state *updates*
    if (cbRef.current) {
      cbRef.current(state);
      cbRef.current = null; // reset callback after execution
    }
  }, [state]);
  return [state, setStateCallback];
}
打字稿版本
function useStateCallback<T>(
  initialState: T
): [T, (state: T, cb?: (state: T) => void) => void] {
  const [state, setState] = useState(initialState);
  const cbRef = useRef<((state: T) => void) | undefined>(undefined); // init mutable ref container for callbacks
  const setStateCallback = useCallback((state: T, cb?: (state: T) => void) => {
    cbRef.current = cb; // store current, passed callback in ref
    setState(state);
  }, []); // keep object reference stable, exactly like `useState`
  useEffect(() => {
    // cb.current is `undefined` on initial render,
    // so we only invoke callback on state *updates*
    if (cbRef.current) {
      cbRef.current(state);
      cbRef.current = undefined; // reset callback after execution
    }
  }, [state]);
  return [state, setStateCallback];
}

进一步信息:React Hooks FAQ:是否有类似实例变量的东西?

工作示例

const App = () => {
  const [state, setState] = useStateCallback(0);
  const handleClick = () =>
    setState(
      prev => prev + 1,
      // important: use `s`, not the stale/old closure value `state`
      s => console.log("I am called after setState, state:", s)
    );
  return (
    <div>
      <p>Hello Comp. State: {state} </p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}
function useStateCallback(initialState) {
  const [state, setState] = useState(initialState);
  const cbRef = useRef(null);
  const setStateCallback = useCallback((state, cb) => {
    cbRef.current = cb; 
    setState(state);
  }, []);
  useEffect(() => {
    if (cbRef.current) {
      cbRef.current(state);
      cbRef.current = null;
    }
  }, [state]);
  return [state, setStateCallback];
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<script>var { useReducer, useEffect, useState, useRef, useCallback } = React</script>
<div id="root"></div>

带有react16.x和向上,如果要使用useState钩在状态更改上调用回调函数,则可以使用附加到状态更改的useEffect钩。

import React, { useEffect } from "react";
useEffect(() => {
  props.getChildChange(name); // using camelCase for functions is recommended.
}, [name]); // this will call getChildChange on initial render and when ever name changes.

实际上,使用React Hooks时应避免使用this。它会引起副作用。这就是React团队创建react hooks的原因。

如果您删除试图绑定this的代码,则只需将ParentsetName传递给Child,然后将其称为handleChange。清洁器代码!

function Parent() {
  const [Name, setName] = useState("");
  return <div> {Name} :
    <Child setName={setName} ></Child>
  </div>
}
function Child(props) {
  const [Name, setName] = useState("");
  function handleChange(ele) {
    setName(ele.target.value);
    props.setName(ele.target.value);
  }
  return (<div>
    <input onChange={handleChange} value={Name}></input>
  </div>);
} 

此外,您不必创建两个Name的副本(一个在Parent中,另一个在Child中)。坚持"真实的单一来源"原理,Child不必拥有状态Name,而是从Parent接收到的。清洁器节点!

function Parent() {
  const [Name, setName] = useState("");
  return <div> {Name} :
    <Child setName={setName} Name={Name}></Child>
  </div>
}
function Child(props) {    
  function handleChange(ele) {
    props.setName(ele.target.value);
  }
  return (<div>
    <input onChange={handleChange} value={props.Name}></input>
  </div>);
} 

我们可以编写自定义函数,如果状态中的任何更改

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const useStateCallbackWrapper = (initilValue, callBack) => {
  const [state, setState] = useState(initilValue);
  useEffect(() => callBack(state), [state]);
  return [state, setState];
};
const callBack = state => {
  console.log("---------------", state);
};
function App() {
  const [count, setCount] = useStateCallbackWrapper(0, callBack);
  return (
    <div className="App">
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>+</button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

`

实现这一目标的另一种方法:

const [Name, setName] = useState({val:"", callback: null});
React.useEffect(()=>{
  console.log(Name)
  const {callback} = Name;
  callback && callback();
}, [Name]);
setName({val:'foo', callback: ()=>setName({val: 'then bar'})})

您可以利用usecallback钩子来执行此操作。

function Parent() {
  const [name, setName] = useState("");
  const getChildChange = useCallback( (updatedName) => {
    setName(updatedName);
  }, []);
  return <div> {name} :
    <Child getChildChange={getChildChange} ></Child>
  </div>
}
function Child(props) {
  const [name, setName] = useState("");
  function handleChange(ele) {
    setName(ele.target.value);
    props.getChildChange(ele.target.value);
  }
  function collectState() {
    return name;
  }
  return (<div>
    <input onChange={handleChange} value={name}></input>
  </div>);
}

function Parent() {
  const [Name, setName] = useState("");
  getChildChange = getChildChange.bind(this);
  function getChildChange(value) {
    setName(value);
  }
  return <div> {Name} :
    <Child getChildChange={getChildChange} ></Child>
  </div>
}
function Child(props) {
  const [Name, setName] = useState("");
  handleChange = handleChange.bind(this);
  collectState = collectState.bind(this);
  
  function handleChange(ele) {
    setName(ele.target.value);
  }
  function collectState() {
    return Name;
  }
  
   useEffect(() => {
    props.getChildChange(collectState());
   });
  return (<div>
    <input onChange={handleChange} value={Name}></input>
  </div>);
} 

useEffect充当componentdidmount,componentDidupdate,因此更新状态后它将工作

相关内容

  • 没有找到相关文章

最新更新