Reactjs 采用动态数据属性的React自定义钩子

Reactjs 采用动态数据属性的React自定义钩子,reactjs,rest,react-hooks,Reactjs,Rest,React Hooks,因此,我阅读了这些关于使用自定义挂钩获取数据的博客文章,例如,我们有一个自定义挂钩来执行API调用、设置数据、可能的错误以及spinny isFetching布尔值: export const useFetchTodos = () => { const [data, setData] = useState(); const [isFetching, setIsFetching] = useState(false); const [error, setError] =

因此,我阅读了这些关于使用自定义挂钩获取数据的博客文章,例如,我们有一个自定义挂钩来执行API调用、设置数据、可能的错误以及spinny isFetching布尔值:

export const useFetchTodos = () => {
    const [data, setData] = useState();
    const [isFetching, setIsFetching] = useState(false);
    const [error, setError] = useState();
    useEffect(() => {
      setIsFetching(true);
      axios.get('api/todos')
        .then(response => setData(response.data)
        .catch(error => setError(error.response.data)
        .finally(() => setFetching(false);
      }, []);
     return {data, isFetching, error};
}
然后在组件的顶层,我们只需调用
const{data,error,fetching}=useftchtodos()和所有伟大的我们呈现我们的组件与所有TODO抓取

我不明白的是,我们如何根据组件的内部状态将动态数据/参数发送到钩子,而不破坏钩子的规则

例如,假设我们有一个
useFetchTodoById(id)
hook,它的定义方式与上面的定义方式相同,我们如何传递该
id
?假设呈现TODO的
TodoList
组件如下所示:

export const TodoList = (props) => {
    const [selectedTodo, setSelectedTodo] = useState();
    
    useEffect(() => {
      useFetchTodoById(selectedTodo.id) --> INVALID HOOK CALL, cannot call custom hooks from useEffect, 
        and also need to call our custom hooks at the "top level" of our component
    }, [selectedTodo]);

    return (<ul>{props.todos.map(todo => (
            <li onClick={() => setSelectedTodo(todo.id)}>{todo.name}</li>)}
        </ul>);
}
export const TodoList=(道具)=>{
const[selectedTodo,setSelectedTodo]=useState();
useffect(()=>{
useFetchTodoById(selectedTodo.id)-->钩子调用无效,无法从useEffect调用自定义钩子,
还需要在组件的“顶层”调用自定义挂钩
},[selectedTodo]);
return(
    {props.todos.map(todo=>(
  • setSelectedTodo(todo.id)}>{todo.name}
  • )}
); }
我知道对于这个特定的用例,我们可以通过道具传递我们的
selectedTodo
,并在组件的顶部调用我们的
useFetchTodoById(props.selectedTodo.id)
,但我只是说明了我遇到的这个模式的问题,我们并不总是能够在道具中接收我们需要的动态数据


另外--我们如何将此模式应用于具有动态数据属性的
POST/PUT/PATCH
请求?

您应该有一个基本的
useFetch
钩子,钩子接受url,并在url更改时进行抓取:

const useFetch = (url) => {
  const [data, setData] = useState();
  const [isFetching, setIsFetching] = useState(false);
  const [error, setError] = useState();
  
  useEffect(() => {
    if(!url) return;

    setIsFetching(true);
    axios.get(url)
      .then(response => setData(response.data))
      .catch(error => setError(error.response.data))
      .finally(() => setFetching(false));
  }, [url]);

  return { data, isFetching, error };
};
现在,您可以从这个基本钩子创建其他自定义钩子:

const useFetchTodos = () => useFetch('api/todos');
您还可以使其响应动态变化:

const useFetchTodoById = id => useFetch(`api/todos/${id}`);
您可以在组件中使用它,而无需将其包装在
useffect
中:

export const TodoList = (props) => {
  const [selectedTodo, setSelectedTodo] = useState();
  
  const { data, isFetching, error } = useFetchTodoById(selectedTodo.id);

  return (
    <ul>{props.todos.map(todo => (
      <li onClick={() => setSelectedTodo(todo.id)}>{todo.name}</li>)}
    </ul>
  );
};
export const TodoList=(道具)=>{
const[selectedTodo,setSelectedTodo]=useState();
const{data,isFetching,error}=useFetchTodoById(selectedTodo.id);
返回(
    {props.todos.map(todo=>(
  • setSelectedTodo(todo.id)}>{todo.name}
  • )}
); };
Ah所以我的误解是我认为我需要依靠我的useEffect来跟踪状态变化。另一个问题,你会如何处理将新数据发布到api?例如
useCreateTodo(newTodo)
-我们不能只在组件顶部调用它,因为我们的
newTodo
状态在挂载时是未定义的,将自定义钩子包装在if中是无效的。唯一的另一个选择是将if undefined检查包装在钩子本身的主体内?如果没有url,您应该避免更改状态,并调用API。I在
useffect
中,检查url是否不存在
!url
,如果是,则返回。请参阅更新的答案。啊,那么,相同的概念也适用于我的
useCreateTodo
。谢谢,您帮了我大忙!