首页 > 解决方案 > 取数据后不断输入useEffect

问题描述

useEffectProfile组件中有这样的:

const [mappedPosts, setMappedPosts] = useState(null);

useEffect(() => {
  fetchMedia();

  if (userPosts) {
    console.log("This keeps entering!");
    const mapped = userPosts.map((post, index) => (
      <View key={index}>
        <Text>{post.title}</Text>
      </View>
    ));

    setMappedPosts(mapped);
  }
}, []);

我的Profile组件返回,

return mappedPosts ? (
  <View>
    {mappedPosts}
  </View>
) : (
  <Spinner />
);

我的问题如下:

Spinner我有组件时呈现:

    useEffect(() => {
      fetchMedia();

      if (userPosts) {...};

        setMappedPosts(mapped);
      }
    }, []);

或者

    useEffect(() => {
      fetchMedia();

      if (userPosts) {...};

        setMappedPosts(mapped);
      }
    }, [mappedPosts]);

当我有适当的数据时:

    useEffect(() => {
      fetchMedia();

      if (userPosts) {...};

        setMappedPosts(mapped);
      }
    }, [userPosts]);

或者

    useEffect(() => {
      fetchMedia();

      if (userPosts) {...};

        setMappedPosts(mapped);
      }
    });

最后两个的问题是,该行console.log("This keeps entering!");反复打印,说明组件一直在重新渲染。我不确定我在这里做错了什么。以下变体也不断重新渲染组件:

 const [mappedPosts, setMappedPosts] = useState(null);

 useEffect(() => {
      fetchMedia();

      if (userPosts && mappedPosts === null) {
           console.log("entered!");
           const mapped = userPosts.map((post, index) => (
                <View key={index}>
                     <Text>{post.title}</Text>
                </View>
           ));

           setMappedPosts(mapped);
      }
 }, [userPosts]);

 console.log("am I being re-rendered?");

 return mappedPosts ? (
      <View>
           {mappedPosts}
      </View>
 ) : (
      <Spinner />
 );

我知道这一点是因为console.log("am I being re-rendered?");不停地打印……即使数据已经在屏幕上正确渲染和显示(我正在使用 react-native)。

Profile组件userPosts从 redux 存储中获取:

const Profile = ({
  navigation,
  posts: { userPosts, loading },
  auth: { isAuthenticated },
  fetchMedia,
  checkAuth
}) => {

    const [mappedPosts, setMappedPosts] = useState(null);

    useEffect(() => {
       fetchMedia();
.......

编辑:

fetchMedia: _

export const fetchMedia = () => async dispatch => {
  dispatch({
    type: FETCH_MEDIA
  });

  try {
    const response = await axios.get(`http://${GATEWAY}:5000/api/posts/user`);

    dispatch({
      type: MEDIA_SUCCESS,
      payload: response.data
    });
  } catch (err) {
    dispatch({
      type: MEDIA_FAIL
    });
  }
};

减速机:

const initialState = {
  userPosts: null,
  loading: false
};

export default function(state = initialState, action) {
  const { type, payload } = action;

  switch (type) {
    case FETCH_MEDIA:
      return {
        ...state,
        loading: true
      };

    case MEDIA_SUCCESS:
      return {
        ...state,
        userPosts: payload,
        loading: false
      };

    case MEDIA_FAIL:
      return {
        ...state,
        loading: false
      };

    default:
      return state;
  }
}

标签: reactjsreact-nativereact-hooks

解决方案


您的答案可能会起作用,因为数据只会被获取一次并且userPost永远不会更改参考。

通常将 REST 数据置于状态比您所做的要复杂一些。如果您需要数据,则容器将选择如下数据:

const NOT_REQUESTED = {requested:false}
state => state.data.someData || NOT_REQUESTED

然后组件可以请求数据,如果它没有被请求

useEffect(()=>requested || fetchData(),[requested])

reducer 将设置请求和加载作为对请求操作的响应:

{
  ...state,
  data: {
    ...state.data,
    someData: { requested: true, loading: true },
  },
};

现在,当您的组件将重新渲染但fetchData由于请求为真而未被调用时。

当请求成功时,reducer 可以将结果写入数据成功操作:

{
  ...state,
  data: {
    ...state.data,
    someData: {
      ...state.data.someData,
      loading: false,
      data: action.data,
    },
  },
};

这与服务器端过滤、排序、陈旧数据或错误处理无关,但我希望你明白这一点。

如果您希望组件调度操作以加载数据,那么您的容器/选择器需要生成指示数据是否已被请求的道具。


推荐阅读