提取数据后继续输入useEffect

时间:2019-08-31 08:25:05

标签: reactjs react-native react-hooks

我的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组件从redux存储中获取userPosts

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

2 个答案:

答案 0 :(得分:2)

您的答案可能会起作用,因为数据只会被提取一次,而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 },
  },
};

现在,当您的组件将重新呈现但由于请求为true时,未调用fetchData时。

请求成功后,reducer可以将结果写到数据成功操作上:

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

这与服务器端过滤,排序,陈旧数据或错误处理无关,但我希望您能理解。

如果您希望组件分派操作以加载数据,则您的容器/选择器需要产生道具来指示是否已请求数据。

答案 1 :(得分:2)

所以我知道了。问题是组件每次更改时都会调用fetchMedia。因此,一旦userPosts被提取..它们又被提取了。然后再次。然后再次。这就是组件不断重新渲染的原因。这是我所做的更改:

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

    setMappedPosts(mapped);
  } else {
    fetchMedia();
  }
}, [userPosts]);