在功能组件React中调用提取功能

时间:2020-04-12 13:29:30

标签: javascript reactjs typescript redux react-redux

我尝试了很多方法在渲染前仅获取一次数据,但是有一些问题:

1)我不能在componentDidMount中调用dispatch,因为有规则规定我只能在功能组件中进行此操作

2)如果我尝试在Functional组件的开头调用fetch函数,它将开始无限重渲染,因为fetch函数每次都会调用并更改redux存储区中的状态

3)我找到了useEffect的解决方案,但它像第一点一样会产生异常"Invalid hook call"

如何在此组件中仅调用一次提取功能?

这是我的component

   import React, { useEffect } from "react";
import { useParams as params} from "react-router-dom";
import { VolunteerCardList } from "./VolunteerCardList";
import { AnimalNeeds } from "./AnimalNeeds";
import { AppState } from "../reducers/rootReducer";
import { connect } from "react-redux";
import { Page404 } from "./404";
import { fetchAnimal } from "../actions/animalAction";
import { Dispatch } from "redux";
import { IAnimalCard } from "../interfaces/Interfaces";

const AnimalCard: React.FC<Props> = ({animal, loading, fetch}) => {
    useEffect(() => {   
            fetch(); //invalid hook call????
    }, [])


    return (
        <div className="container">
            some html
        </div>
    )
}

interface RouteParams {
    shelterid: string,
    animalid: string,
}

interface mapStateToPropsType {
    animal: IAnimalCard,
    loading : boolean
}

const mapStateToProps = (state: AppState) : mapStateToPropsType=> {
    return{
        animal: state.animals.animal,
        loading: state.app.loading
    }
}

interface mapDispatchToPropsType {
    fetch: () => void;
}

const mapDispatchToProps = (dispatch: Dispatch<any>) : mapDispatchToPropsType => ({
    fetch : () => {
        const route = params<RouteParams>();
        dispatch(fetchAnimal(route.shelterid, route.animalid));
    }
})

type Props  = ReturnType<typeof mapStateToProps> & ReturnType<typeof mapDispatchToProps>;

export default connect(mapStateToProps, mapDispatchToProps as any)(AnimalCard);

这是我的reducer

export const animalReducer = (state: AnimalReducerType = initState, action: IAction) => {

switch (action.type) {
    case AnimalTypes.FETCH_ANIMAL:
            return {...state, animal: action.payload};
        break;

    default:
        return state;
        break;
}

这是动作:

export interface IFetchAnimalAction  {
    type: AnimalTypes.FETCH_ANIMAL,
    payload: IAnimalCard
}

export type IAction = IFetchAnimalAction;

export const fetchAnimal = (shelterId : string, animalId: string) => {
    return async (dispatch: Dispatch)  => {
        const response = await fetch(`https://localhost:44300/api/animals/${animalId}`);
        const json = await response.json();
        dispatch<IFetchAnimalAction>({type: AnimalTypes.FETCH_ANIMAL, payload: json})
    }
} 

1 个答案:

答案 0 :(得分:0)

这以旧的生命周期方法componentDidMount运行:

useEffect(() => {   
  fetch(); //invalid hook call????
}, [])

我猜想您要复制的行为是componentWillMount所迭代的行为,而任何标准钩子都无法做到这一点。为此,我的首选解决方案是让您获取一些loadingState,最明确地表示为:

const AnimalCard: React.FC<Props> = ({animal, loading, fetch}) => {
    const [isLoading, setIsLoading] = useState<boolean>(false);

    useEffect(() => {   
      fetch().then(res => {
        // Do whatever with res
        setIsLoading(true);
      } 
    }, [])

    if(!isLoading){
      return null
    }

    return (
        <div className="container">
            some html
        </div>
    )
}