状态更改时useEffect无法运行

时间:2019-10-05 20:19:08

标签: react-native react-hooks asyncstorage

我有一个屏幕(MyPics.js),其中显示了用户从另一个屏幕中选择的图像集合。我从异步存储中获取了选定的图像。

如果我选择图像,然后重新启动模拟器,则一切正常。当我导航到MyPics.js屏幕时,可以看到先前选择的图像中存储在AsyncStorage中的所有图像。

  const MyPicsScreen = props => {
    const [picList, setpicList] = useState([]);

    useEffect(() => {
      console.log("I'm in!! picList data is: " +  picList);
      AsyncStorage.getItem("mypics").then((response) => {
      const currentData = JSON.parse(response);
      setpicList(currentData);
      console.log("Current picList data will be: " + currentData);
    });
   }, []);


  return (
<View style={styles.wrapper}>
  <ScrollView>
    <View style={{flexDirection: "column", justifyContent: "center", alignItems: "center"}}>

      {picList ? picList.map((item, index) => {
        return (
            <View key={index} style={styles.viewItem}>
              <Image style={{width: 200, height: 131}} source={Images[PicList[item][3]]} />
            </View>
          );
        }
      ) : <View><Text>You haven't selected any pics yet</Text></View>}

    </View>
  </ScrollView>
</View>
   );
 };

终端显示:

  I'm in!! picList data is:  //No data, as expected. Nothing is retrieved yet, then...
  Current picList data: pic001,pic007,pic099 // That shows, correctly, what's stored and screen shows those images 

但是,如果我添加图像,除非重新启动模拟器,否则不会显示新图像。另外,控制台中没有读出数据,因此useEffect不会运行以获取数据并重置状态。

我假设返回MyPics屏幕会导致重新渲染,但是我可能是错的。

我在MyPics.js屏幕上做了3个按钮,它们在异步存储上手动运行removeItem或setItem或getItem,然后删除或设置或获取图像,然后更新picList状态。

可行。

当我使用按钮时,它会获取或删除先前设置的图像或设置新图像,然后屏幕会重新渲染以显示状态更改。

因此,当我导航到MyPics.js屏幕时,useEffect没有运行。它仅在第一个渲染器上运行。

当我将picList状态添加为依赖项时,

  }, [picList]);

它可以工作,但控制台正在无限循环中运行。

那正常吗?我应该忽略无限滚动的控制台还是错过了一步?我应该使用焦点侦听器在重新访问时重新呈现页面吗,因为只有当我返回MyPics屏幕时才需要新数据。

3 个答案:

答案 0 :(得分:0)

docs

  

如果您要运行效果并仅将其清理一次(在挂载和   卸载),则可以传递一个空数组([])作为第二个参数。这个   告诉React你的效果不依赖于道具的任何值   或状态,因此它不需要重新运行。这不是特殊处理   case —直接从依赖关系数组始终如何得出   有效。

因此,将一个空数组传递到您的useEffect大致等效于useEffect和{{1}(除了componentDidMount在初始绘制后在之后触发 }类组件的功能。

答案 1 :(得分:0)

经过大量的痛苦和浪费的时间,这有效:

 useEffect(() => {
  AsyncStorage.getItem("mypics").then((response) => {
  setpicList(JSON.parse(response);
});
}, []);

const getList = useCallback(() => {
  AsyncStorage.getItem("mypics").then((value) =>{
  setpicList(JSON.parse(value));
});
}, [picList]);

在此线程中可以找到一些非常实用的功能组件示例:

React navigation didfocus event listener works differently between class component and functional component

返回到屏幕时需要进行焦点检测,以便useEffect函数再次运行。

答案 2 :(得分:0)

谢谢@Kelvin Aitken和@Danny Buonocore的支持

我想知道为什么useEffect钩子只在初始加载时起作用,而在我尝试对更多项目进行分页时却失败了。

后来我发现我应该在[]中传递任何依赖项/状态,以告诉钩子随时呈现状态更改。


const [fetchItemInput, SetFetchItemInput] = useState(input);

const fetchMoreItemBtn = (nextCursor) => {
    const newInput = { ...fetchItemInput };
    newInput.after = nextCursor;
    return SetFetchItemInput(newInput);
  };

  useEffect(() => {

    handleFetchItem(fetchItemInput)
      .then((res) => {
            ...
      })
      .catch((error) => {
            ...
      });
    return () => {};
  }, [fetchItemInput]);       // Any changes run the effect

再次感谢您的支持。