无法在渲染不同组件时更新组件 react-navigation

huangapple go评论56阅读模式
英文:

Cannot update a component while rendering a different component react-navigation

问题

我用expo和react native构建一个应用。在我的项目中,我有一个包含三个stackScreen的stackNavigator,还有一个具有静态异步函数的DatabaseManager类。在我的组件中,我使用useState和useEffect加载数据并显示它们。
当我从第一个屏幕移到第二个屏幕时,我收到一个错误:

>警告:在渲染不同组件(%s)时无法更新组件(%s)。要定位%s中坏的setState()调用,请按照堆栈跟踪的描述在https://reactjs.org/link/setstate-in-render%s,StackNavigator,Screen,Screen中查找。

我想这个警告是我有时需要在屏幕之间导航时点击两次的原因。

这是我的一部分代码:

export default class DatabaseManager {
    ...
    static async getSplits(){
        if (!this.db)
            await this.openDatabase();
        const query = "select distinct day from exercises";
        const resultQuery = await this.executeSql(query, []);
        const result = [];
        var rows = resultQuery.rows;
        for (let i = 0; i < rows.length; i++) {
            var item = rows.item(i);
            result.push({split: item.DAY});
        }
        return result;

    }

    static async getExercises(split){
        if (!this.db)
            await this.openDatabase();
        const query = "select distinct name from exercises where day = ? order by number";
        const resultQuery = await this.executeSql(query, [split]);
        const result = [];
        var rows = resultQuery.rows;
        for (let i = 0; i < rows.length; i++) {
            var item = rows.item(i);
            result.push({name: item.NAME});
        }
        return result    
   }

}

App.js

//...
function HomeStackScreen() {


  return (
    <HomeStack.Navigator initialRouteName='Home'  >
      <HomeStack.Screen name="Home" component={Home} options={{title:'Splits'} }/>
      <HomeStack.Screen name="Screen" component={Screen} />
    </HomeStack.Navigator>
  );
}
...
export default function Home ({navigation}){
  const [splits, setSplits] = useState([{ split:''}]);
  const handlePress = async (split) => {

    navigation.navigate('Screen', {split: split});
    };

  useEffect(() => {
      const dataFetch = async () => {
        const data = await DatabaseManager.getSplits();
        setSplits(data);
      }
      dataFetch();
  }, [])

    return (
        <View style={styleHome.container}>
            <ScrollView style={styleHome.scrollViewContainer}>
              {splits.map((split, index) => (
                <View style={styleHome.touchableContainer} key={index}>
                  <Pressable
                    key={split.split}
                    style={styleHome.touchable}
                    activeOpacity={1}
                    onPress={() => handlePress(split.split)}
                  >
                    <Text style={styleHome.textTouchable}>{split.split}</Text>
                  </Pressable>
                </View>
  
              ))}
            </ScrollView>
          </View>
      
    );

第二个屏幕与此类似。

我尝试使用useFocusEffectenableFreezeuseFocus。我还尝试在导航到新屏幕之前放置一个加载屏幕,但没有解决问题。通过使用一些console.log,我发现我的代码似乎是正确的,Home组件在导航到其他组件后没有重新渲染。

英文:

I'm building an app using expo and react native. In my project, I have a stackNavigator containing three stackScreen and I also have a DatabaseManager class with static async function. In my components, I use useState and useEffect to load my data and display them.
When I move from the first Screen to the second one, I got an error :

>Warning: Cannot update a component (%s) while rendering a different component (%s). To locate the bad setState() call inside %s, follow the stack trace as described in https://reactjs.org/link/setstate-in-render%s, StackNavigator, Screen, Screen.

This warning is, I suppose the reason why I need to tap 2 times on the screen to navigate between screens sometimes.

Here's a part of my code:

export default class DatabaseManager {
    ...
    static async getSplits(){
        if (!this.db)
            await this.openDatabase();
        const query = &quot;select distinct day from exercises&quot;;
        const resultQuery = await this.executeSql(query, []);
        const result = [];
        var rows = resultQuery.rows;
        for (let i = 0; i &lt; rows.length; i++) {
            var item = rows.item(i);
            result.push({split: item.DAY});
        }
        return result;

    }

    static async getExercises( split){
        if (!this.db)
            await this.openDatabase();
        const query = &quot;select distinct name from exercises where day = ? order by number&quot;;
        const resultQuery = await this.executeSql(query, [split]);
        const result = [];
        var rows = resultQuery.rows;
        for (let i = 0; i &lt; rows.length; i++) {
            var item = rows.item(i);
            result.push({name: item.NAME});
        }
        return result    
   }

}

App.js

//...
function HomeStackScreen() {


  return (
    &lt;HomeStack.Navigator initialRouteName=&#39;Home&#39;  &gt;
      &lt;HomeStack.Screen name=&quot;Home&quot; component={Home} options={{title:&#39;Splits&#39;} }/&gt;
      &lt;HomeStack.Screen name=&quot;Screen&quot; component={Screen} /&gt;
    &lt;/HomeStack.Navigator&gt;
  );
}
...
export default function Home ({navigation}){
  const [splits, setSplits] = useState([{ split:&#39;&#39;}]);
  const handlePress = async (split) =&gt; {

    navigation.navigate(&#39;Screen&#39;, {split: split});
    };

  useEffect(() =&gt; {
      const dataFetch = async () =&gt; {
        const data = await DatabaseManager.getSplits();
        setSplits(data);
      }
      dataFetch();
  }, [])

    return (
        &lt;View style={styleHome.container}&gt;
            &lt;ScrollView style={styleHome.scrollViewContainer}&gt;
              {splits.map((split, index) =&gt; (
                &lt;View style={styleHome.touchableContainer} key={index}&gt;
                  &lt;Pressable
                    key={split.split}
                    style={styleHome.touchable}
                    activeOpacity={1}
                    onPress={() =&gt; handlePress(split.split)}
                  &gt;
                    &lt;Text style={styleHome.textTouchable}&gt;{split.split}&lt;/Text&gt;
                  &lt;/Pressable&gt;
                &lt;/View&gt;
  
              ))}
            &lt;/ScrollView&gt;
          &lt;/View&gt;
      
    );

The second screen is similar to this.

I tried to use useFocusEffect, enableFreeze and useFocus. I also tried to put a Loading Screen before navigating to a new screen, nothing solve the issue. By using some console.log, I found out that my code seems to be correct, the Home component doesn't re render after navigating to the other component.

答案1

得分: 0

我发现了解决方案:我在第二个屏幕中的 navigation.setOptions() 中有问题...
我将其包装在 useEffect() 中,现在它运行正常。

我在这里找到了解决方案:https://github.com/react-navigation/react-navigation/issues/9478#issuecomment-813031134

英文:

I found out the solution: I just had a bad navigation.setOptions() in the second screen ...
I wrapped it in the useEffect() and it works fine.

I found the solution there: https://github.com/react-navigation/react-navigation/issues/9478#issuecomment-813031134

huangapple
  • 本文由 发表于 2023年2月19日 06:25:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/75496769.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定