programing

응답에 useState 훅이 있는 콜백을 사용하는 방법

showcode 2023. 3. 31. 23:03
반응형

응답에 useState 훅이 있는 콜백을 사용하는 방법

후크가 달린 기능성 컴포넌트를 사용하고 있습니다.자녀에서 부모 상태를 업데이트해야 합니다.Parent에서 prop 기능을 사용하고 있습니다.현재 상태가 아닌 이전 상태가 되는 것을 제외하고 모든 것이 정상적으로 작동합니다.useState 훅 설정 현재 상태를 설정하기 전에 프로펠러 기능이 실행됩니다.useState 콜 후에 콜백 기능이 실행되기를 어떻게 기다릴 수 있습니까?클래스 베이스의 컴포넌트에서 setState(state, callback)와 같은 것을 찾고 있습니다.

코드 스니펫은 다음과 같습니다.

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>);
} 

useEffect/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)위해서useState

다음 구현은 클래스의 원래 콜백에 매우 가깝습니다.

승인된 답변에 대한 개선 사항:

  1. 초기 렌더링 시 콜백 실행이 생략됨 - 상태 업데이트 시 콜백 실행만 수행하려고 합니다.
  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];
}
TypeScript version
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];
}

상세 정보: Respect 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>

React 16.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.

사실, 당신은 그것을 사용하는 것을 피해야 한다.this리액트 훅 사용 시.그것은 부작용을 일으킨다.그래서 리액션 팀이react hooks.

바인드를 시도하는 코드를 삭제한 경우this그냥 지나가면 돼요.setNameParent로.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>);
} 

게다가 2개의 복사본을 작성할 필요가 없습니다.Name(1인치)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>);
} 

상태가 변경되면 callBack 함수를 호출하는 커스터마이즈 함수를 작성할 수 있습니다.

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>);
} 

useEffectcomponentDidMount, componentDidUpdate로 동작하기 때문에 상태를 갱신하면 동작합니다.

언급URL : https://stackoverflow.com/questions/54954091/how-to-use-callback-with-usestate-hook-in-react

반응형