英文:
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>
);
第二个屏幕与此类似。
我尝试使用useFocusEffect
,enableFreeze
和useFocus
。我还尝试在导航到新屏幕之前放置一个加载屏幕,但没有解决问题。通过使用一些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 = "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>
);
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论