React Hook: правильный способ использования пользовательского хука для обработки события onClick? - PullRequest
1 голос
/ 23 апреля 2020

Как сказано в заголовке, как правильно использовать пользовательский хук для обработки события onClick?

Это приложение codesandbox будет отображать новую цитату на экране, когда пользователь щелкает поиск button.

function App() {
  const [{ data, isLoading, isError }, doFetch] = useDataApi(
    "https://api.quotable.io/random"
  );

  return (
    <Fragment>
      <button disabled={isLoading} onClick={doFetch}>
        Search
      </button>
      {isError && <div>Something went wrong ...</div>}
      {isLoading ? <div>Loading ...</div> : <div>{data.content}</div>}
    </Fragment>
  );
}

Я создал пользовательский хук с именем useDataApi(), который будет получать новую цитату из API. Чтобы обновить цитату, когда пользователь нажимает кнопку внутри useDataApi(), я создал handleClick(), который изменит значение щелчка для запуска повторного рендеринга. И эта handleClick() функция вернется обратно к App()

const useDataApi = initialUrl => {
  const [data, setData] = useState("");
  const [click, setClick] = useState(true);
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);

  const handleClick = () => {
    setClick(!click);
  };

  useEffect(() => {
    const fetchData = async () => {
      setIsError(false);
      setIsLoading(true);
      try {
        const result = await axios(initialUrl);

        setData(result.data);
      } catch (error) {
        setIsError(true);
      }
      setIsLoading(false);
    };
    fetchData();
  }, [initialUrl, click]);

  return [{ data, isLoading, isError }, handleClick];
};

Это работает, однако я не думаю, что это правильное решение.

Я также пытался переместить fetchData() из useEffect и вернуть fetchData(), и это тоже работает. Но согласно React Do c говорится, что рекомендуется перемещать функции внутри useEffect.

const useDataApi = initialUrl => {
  const [data, setData] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);

  const fetchData = async () => {
    setIsError(false);
    setIsLoading(true);
    try {
      const result = await axios(initialUrl);
      setData(result.data);
    } catch (error) {
      setIsError(true);
    }
    setIsLoading(false);
  };

  useEffect(() => {
    fetchData();
  }, []);

  return [{ data, isLoading, isError }, fetchData];
};

. Кроме того, для создания приложений такого типа способ, которым я пользуюсь, подойдет или есть другое правильное решение, например, не использовать useEffects или не создавать какой-либо пользовательский Hook? Спасибо

Ответы [ 2 ]

3 голосов
/ 23 апреля 2020

Не уверен, что это правильно, но вот мое решение.

const useDataApi = initialUrl => {
  const [data, setData] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);

  const doFetch = async () => {
    setIsError(false);
    setIsLoading(true);
    try {
      const result = await axios(initialUrl);

      setData(result.data);
    } catch (error) {
      setIsError(true);
    }
    setIsLoading(false);
  };

  return [{ data, isLoading, isError }, doFetch];
};

Кстати, не изменяйте состояние напрямую.

const handleClick = () => {
    setClick(!click);         // don't do this
    setClick(prev => !prev);    // use this
};
1 голос
/ 23 апреля 2020

Ваша реализация в порядке. Мы также используем нечто подобное. Надеюсь, что вы найдете ее полезной.

function useApi(promiseFunction, deps, shouldRun=true){
  // promisFunction returns promise
  const [loading, setLoading] = useState(false)
  const [data, setData] = useState(false)
  const [error, setError] = useState(false)
  
  const dependencies: any[] = useMemo(()=>{
    return [...dependencyArray, shouldRun]
  },[...dependencyArray, shouldRun])
  
  const reload = () => {
    async function call() {
      try {
        setError(null)
        setLoading(true)
        const res = await promiseFunction();
      }
      catch (error) {
        setError(error)
      }
      finally {
        setLoading(false)
      }
    }
    call();
  }

  useEffect(() => {
    if(!shouldRun) return
    setResult(null) //no stale data
    reload()
  }, dependencies)
  
  return {loading, error, data, reload, setState: setData}
}

Ниже приведен пример того, как его использовать.

function getUsersList(){
  return fetch('/users')
}

function getUserDetail(id){
  return fetch(`/user/${id}`)
}
const {loading, error, data }  = useApi(getUsersList, [], true)

const {loading: userLoading, error: userError, data: userData}
 = useApi(()=>getUserDetail(id), [id], true)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...