设置状态需要双击
set state required double click
我有一个 useState 挂钩,用于存储是否应显示菜单,在我的 jsx 渲染器中,我有一个 touchableOpacity,当我更改它时,它应该更新我的状态并显示菜单,但状态不更新,除非我给它点击不止一次 touchable。
在 showExpenses 函数中更新 expenseActivitie 状态时会发生此错误。
Screen:
import React, { useContext, useEffect, useState } from 'react'
import { Dimensions, Text, TouchableOpacity, View } from 'react-native'
import { StackScreenProps } from '@react-navigation/stack';
import { RootStackParams } from '../../navigator/Navigator';
import { commonStyles } from '../../styles/commonStyles';
import { ThemeContext } from '../../contexts/theme/ThemeContext';
import LinearGradient from 'react-native-linear-gradient';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faExclamationCircle, faFilter } from '@fortawesome/free-solid-svg-icons';
import { ExpenseActivitiesRQ } from '../../interfaces/viatics/ExpenseActivitiesRQ';
import { useActivities } from '../../hooks/viatics/useActivities';
import { AuthContext } from '../../contexts/auth/AuthContext';
import { FlatList, ScrollView } from 'react-native-gesture-handler';
import { GActivities } from '../../interfaces/viatics/GActivities';
import Icon from 'react-native-vector-icons/Ionicons'
import Moment from 'moment';
import { setStateActivity } from '../../helpers/viatics/setStateActivity';
import { setStateColor } from '../../helpers/viatics/setStateColor';
import { ExpensesScreen } from './ExpensesScreen';
import { ActivityIndicator } from 'react-native';
import { Col, Grid, Row } from 'react-native-easy-grid';
import { activitiesStyles } from '../../styles/activitiesStyles';
import { MenuActivity } from '../../components/viatics/menuActivity';
import { GExpenses } from '../../interfaces/viatics/GExpenses';
interface Props extends StackScreenProps<RootStackParams, 'ActivitiesListScreen'>{};
export const ActivitiesListScreen = ( { route, navigation }: Props ) => {
const { userData } = useContext( AuthContext );
const request: ExpenseActivitiesRQ = {
IDUser: userData.IDUser,
IDEntity: userData.IDEntityDefault,
excludeImages: true
};
const type = route.params.type;
const { loading, activitiesList } = useActivities( type, request );
const { theme: { colors, secondary, buttonText } } = useContext( ThemeContext );
const [expenseActivitie, setExpenseActivitie] = useState({
showExpense: false,
currentIndex: -1
});
const [menus, setMenus] = useState({
menuExpense: false,
menuActivity: false
});
const [currentExpense, setCurrentExpense] = useState({
menuExpense: false,
data: new GExpenses()
});
useEffect(() => {
switch( type ) {
case 'allActivities':
navigation.setOptions({
title: 'Actividades Generales'
});
break;
case 'pendingApprove':
navigation.setOptions({
title: 'Pendientes por Aprobar'
});
break;
case 'pendingLegalize':
navigation.setOptions({
title: 'Pendientes por Legalizar'
});
break;
default:
navigation.setOptions({
title: 'Activitidades'
});
break;
}
}, []);
const renderActivitieCard = ( activitie: GActivities, index: number ) => {
const bottomPadding: number = ( activitiesList.ListActivities.length === ( index + 1 ) && ( menus.menuActivity || menus.menuExpense ) ) ? 80 : 0;
return (
<>
<View style={{ paddingBottom: bottomPadding }}>
<View style={{ ...activitiesStyles.datesContainer, backgroundColor: colors.primary,}}>
<Text style={{ color: buttonText, fontSize: 12, marginLeft: 4 }}>
{ Moment(activitie.DateSta).format('DD/MMMM/YYYY') }
</Text>
<Icon
name="repeat"
color={ buttonText }
size={ 30 }
/>
<Text style={{ color: buttonText, fontSize: 12 }}>
{ Moment(activitie.DateEnd).format('DD/MMMM/YYYY') }
</Text>
<View style={{ ...activitiesStyles.activityState, backgroundColor: setStateColor(activitie.State) }}>
<Text style={{ textAlign: 'center', color: buttonText }}>{ setStateActivity(activitie.State) }</Text>
</View>
</View>
<View style={{ borderWidth: 2, marginBottom: 10, borderColor: colors.primary, borderBottomLeftRadius: 10, borderBottomRightRadius: 10 }}>
<View style={{ marginTop: 10, marginBottom: 5 }}>
<View style={{ ...activitiesStyles.dataContainer, }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Pasajero: </Text>
<Text style={{color: colors.text}}>{ activitie.UserName }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Actividad: </Text>
<Text style={{color: colors.text}}>{ activitie.Description }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Gastos Registrados: </Text>
<Text style={{color: colors.text}}>{ activitie.countExpenses }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Registrado: </Text>
<Text style={{color: colors.text}}>{ activitie.totalExpense } de { activitie.Budget } </Text>
</View>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-around' }}>
<TouchableOpacity
onPress={ () => showExpenses(index) }
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> Ver Gastos </Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress={ () => navigation.navigate('RegisterExpensesScreen') }
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> Adicionar Gasto </Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress={ () => setMenus({
...menus,
menuActivity: !menus.menuActivity
})}
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> + Opciones </Text>
</LinearGradient>
</TouchableOpacity>
</View>
{ (expenseActivitie.showExpense === false && expenseActivitie.currentIndex === index ) &&
<ExpensesScreen currentActivity={ activitie } menus={ menus } parentCallBack= { handleCallBack } />
}
</View>
</View>
</View>
</>
)
}
const showExpenses = (index: number) => {
setExpenseActivitie({
...expenseActivitie,
showExpense: !expenseActivitie.showExpense,
currentIndex: index
})
}
const handleCallBack = (childData: GExpenses) => {
console.log('childData', childData);
setCurrentExpense({
...currentExpense,
data: childData,
menuExpense: true,
})
}
return (
<>
<View style={{
...commonStyles.container,
alignItems: 'stretch',
bottom: 50,
}}>
<Text style={{
...commonStyles.title,
color: colors.primary,
marginBottom: 10
}}>
Actividades de Gastos
</Text>
<View style={ commonStyles.rightButtonContainer }>
<TouchableOpacity
disabled={( activitiesList.ListActivities.length > 0) ? false : true }
onPress={ () => navigation.navigate('FilterActivitiesScreen') }
style={commonStyles.rightButton}>
<LinearGradient
colors={[colors.primary, secondary]}
style={{
...commonStyles.rightButton,
flexDirection: 'row'
}}
>
<FontAwesomeIcon
style={{
color: buttonText
}}
icon={ faFilter }
size={20} />
<Text style={[commonStyles.buttonText, {
color:'#fff'
}]}>Filtrar</Text>
</LinearGradient>
</TouchableOpacity>
</View>
{
!loading &&
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator
size="large"
animating={ true }
color={ colors.primary }
></ActivityIndicator>
</View>
}
{
( loading && activitiesList.ListActivities.length > 0 )
&&
<View style={{ marginTop: 10, flex: 1, width: '100%' }}>
<FlatList
data={ activitiesList.ListActivities }
keyExtractor={ (activie: GActivities) => activie.IDGroup }
renderItem={ ({ item, index }) => renderActivitieCard( item, index ) }
/>
</View>
}
{
( loading && activitiesList.ListActivities.length === 0 )
&&
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', }}>
<FontAwesomeIcon
icon={ faExclamationCircle }
color={ colors.primary }
size={ 100 }
/>
<Text style={{
...commonStyles.title,
fontSize: 25,
color: colors.primary,
marginBottom: 10
}}>
No se encontraron Actividades
</Text>
</View>
}
</View>
{ menus.menuActivity &&
<MenuActivity />
}
</>
)
}
感谢任何帮助
setExpenseActivitie( prev => {
...prev,
showExpense: !expenseActivitie.showExpense,
currentIndex: index
})
尝试修改您的 showexpenses
函数以使其看起来像这样。
我有一个 useState 挂钩,用于存储是否应显示菜单,在我的 jsx 渲染器中,我有一个 touchableOpacity,当我更改它时,它应该更新我的状态并显示菜单,但状态不更新,除非我给它点击不止一次 touchable。
在 showExpenses 函数中更新 expenseActivitie 状态时会发生此错误。
Screen:
import React, { useContext, useEffect, useState } from 'react'
import { Dimensions, Text, TouchableOpacity, View } from 'react-native'
import { StackScreenProps } from '@react-navigation/stack';
import { RootStackParams } from '../../navigator/Navigator';
import { commonStyles } from '../../styles/commonStyles';
import { ThemeContext } from '../../contexts/theme/ThemeContext';
import LinearGradient from 'react-native-linear-gradient';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faExclamationCircle, faFilter } from '@fortawesome/free-solid-svg-icons';
import { ExpenseActivitiesRQ } from '../../interfaces/viatics/ExpenseActivitiesRQ';
import { useActivities } from '../../hooks/viatics/useActivities';
import { AuthContext } from '../../contexts/auth/AuthContext';
import { FlatList, ScrollView } from 'react-native-gesture-handler';
import { GActivities } from '../../interfaces/viatics/GActivities';
import Icon from 'react-native-vector-icons/Ionicons'
import Moment from 'moment';
import { setStateActivity } from '../../helpers/viatics/setStateActivity';
import { setStateColor } from '../../helpers/viatics/setStateColor';
import { ExpensesScreen } from './ExpensesScreen';
import { ActivityIndicator } from 'react-native';
import { Col, Grid, Row } from 'react-native-easy-grid';
import { activitiesStyles } from '../../styles/activitiesStyles';
import { MenuActivity } from '../../components/viatics/menuActivity';
import { GExpenses } from '../../interfaces/viatics/GExpenses';
interface Props extends StackScreenProps<RootStackParams, 'ActivitiesListScreen'>{};
export const ActivitiesListScreen = ( { route, navigation }: Props ) => {
const { userData } = useContext( AuthContext );
const request: ExpenseActivitiesRQ = {
IDUser: userData.IDUser,
IDEntity: userData.IDEntityDefault,
excludeImages: true
};
const type = route.params.type;
const { loading, activitiesList } = useActivities( type, request );
const { theme: { colors, secondary, buttonText } } = useContext( ThemeContext );
const [expenseActivitie, setExpenseActivitie] = useState({
showExpense: false,
currentIndex: -1
});
const [menus, setMenus] = useState({
menuExpense: false,
menuActivity: false
});
const [currentExpense, setCurrentExpense] = useState({
menuExpense: false,
data: new GExpenses()
});
useEffect(() => {
switch( type ) {
case 'allActivities':
navigation.setOptions({
title: 'Actividades Generales'
});
break;
case 'pendingApprove':
navigation.setOptions({
title: 'Pendientes por Aprobar'
});
break;
case 'pendingLegalize':
navigation.setOptions({
title: 'Pendientes por Legalizar'
});
break;
default:
navigation.setOptions({
title: 'Activitidades'
});
break;
}
}, []);
const renderActivitieCard = ( activitie: GActivities, index: number ) => {
const bottomPadding: number = ( activitiesList.ListActivities.length === ( index + 1 ) && ( menus.menuActivity || menus.menuExpense ) ) ? 80 : 0;
return (
<>
<View style={{ paddingBottom: bottomPadding }}>
<View style={{ ...activitiesStyles.datesContainer, backgroundColor: colors.primary,}}>
<Text style={{ color: buttonText, fontSize: 12, marginLeft: 4 }}>
{ Moment(activitie.DateSta).format('DD/MMMM/YYYY') }
</Text>
<Icon
name="repeat"
color={ buttonText }
size={ 30 }
/>
<Text style={{ color: buttonText, fontSize: 12 }}>
{ Moment(activitie.DateEnd).format('DD/MMMM/YYYY') }
</Text>
<View style={{ ...activitiesStyles.activityState, backgroundColor: setStateColor(activitie.State) }}>
<Text style={{ textAlign: 'center', color: buttonText }}>{ setStateActivity(activitie.State) }</Text>
</View>
</View>
<View style={{ borderWidth: 2, marginBottom: 10, borderColor: colors.primary, borderBottomLeftRadius: 10, borderBottomRightRadius: 10 }}>
<View style={{ marginTop: 10, marginBottom: 5 }}>
<View style={{ ...activitiesStyles.dataContainer, }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Pasajero: </Text>
<Text style={{color: colors.text}}>{ activitie.UserName }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Actividad: </Text>
<Text style={{color: colors.text}}>{ activitie.Description }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Gastos Registrados: </Text>
<Text style={{color: colors.text}}>{ activitie.countExpenses }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Registrado: </Text>
<Text style={{color: colors.text}}>{ activitie.totalExpense } de { activitie.Budget } </Text>
</View>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-around' }}>
<TouchableOpacity
onPress={ () => showExpenses(index) }
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> Ver Gastos </Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress={ () => navigation.navigate('RegisterExpensesScreen') }
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> Adicionar Gasto </Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress={ () => setMenus({
...menus,
menuActivity: !menus.menuActivity
})}
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> + Opciones </Text>
</LinearGradient>
</TouchableOpacity>
</View>
{ (expenseActivitie.showExpense === false && expenseActivitie.currentIndex === index ) &&
<ExpensesScreen currentActivity={ activitie } menus={ menus } parentCallBack= { handleCallBack } />
}
</View>
</View>
</View>
</>
)
}
const showExpenses = (index: number) => {
setExpenseActivitie({
...expenseActivitie,
showExpense: !expenseActivitie.showExpense,
currentIndex: index
})
}
const handleCallBack = (childData: GExpenses) => {
console.log('childData', childData);
setCurrentExpense({
...currentExpense,
data: childData,
menuExpense: true,
})
}
return (
<>
<View style={{
...commonStyles.container,
alignItems: 'stretch',
bottom: 50,
}}>
<Text style={{
...commonStyles.title,
color: colors.primary,
marginBottom: 10
}}>
Actividades de Gastos
</Text>
<View style={ commonStyles.rightButtonContainer }>
<TouchableOpacity
disabled={( activitiesList.ListActivities.length > 0) ? false : true }
onPress={ () => navigation.navigate('FilterActivitiesScreen') }
style={commonStyles.rightButton}>
<LinearGradient
colors={[colors.primary, secondary]}
style={{
...commonStyles.rightButton,
flexDirection: 'row'
}}
>
<FontAwesomeIcon
style={{
color: buttonText
}}
icon={ faFilter }
size={20} />
<Text style={[commonStyles.buttonText, {
color:'#fff'
}]}>Filtrar</Text>
</LinearGradient>
</TouchableOpacity>
</View>
{
!loading &&
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator
size="large"
animating={ true }
color={ colors.primary }
></ActivityIndicator>
</View>
}
{
( loading && activitiesList.ListActivities.length > 0 )
&&
<View style={{ marginTop: 10, flex: 1, width: '100%' }}>
<FlatList
data={ activitiesList.ListActivities }
keyExtractor={ (activie: GActivities) => activie.IDGroup }
renderItem={ ({ item, index }) => renderActivitieCard( item, index ) }
/>
</View>
}
{
( loading && activitiesList.ListActivities.length === 0 )
&&
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', }}>
<FontAwesomeIcon
icon={ faExclamationCircle }
color={ colors.primary }
size={ 100 }
/>
<Text style={{
...commonStyles.title,
fontSize: 25,
color: colors.primary,
marginBottom: 10
}}>
No se encontraron Actividades
</Text>
</View>
}
</View>
{ menus.menuActivity &&
<MenuActivity />
}
</>
)
}
感谢任何帮助
setExpenseActivitie( prev => {
...prev,
showExpense: !expenseActivitie.showExpense,
currentIndex: index
})
尝试修改您的 showexpenses
函数以使其看起来像这样。