按钮在不应该更新的情况下更新状态



我几乎已经实现了这个滑块按钮来做我想要做的事情,但不幸的是,我注意到了一个小错误。为了提供上下文,我有一个主页,上面有一个滑块按钮。当我按下按钮时,它会呈现一个新屏幕。我还有一个名为Screen3的底部选项卡屏幕。目标是按下Screen3上的一个按钮,移动滑块按钮并渲染新屏幕。

我几乎已经成功地实现了这一点。当你第一眼进入Screen3并按下文本时,你可以看到它如我所希望的那样工作。然而,有一个小错误,如果你遵循这些步骤,你可以完全复制我所指的。

我已经提供了下面的一些代码,但这个小吃演示提供了你需要的一切。只要确保你在IOS或Android 中运行它

要重现错误,请执行以下操作

1.(单击底部选项卡栏中的Screen3,然后单击文本。它会把你带到";映射";屏幕以及更改滑块按钮。这正是我想要的

2.(现在单击滑块按钮,特别是"列表"。它会将屏幕更改回它最初是

3.(现在对于bug,如果你点击返回屏幕3,然后立即点击主页再次在底部的选项卡栏上,您可以看到我所指的bug。它将按钮更改为";映射";屏幕,即使它没有被渲染。

这是大部分代码,您可能可以在我提供的主页和滑块上进行调试。演示包含了其余的代码。

App.js

function MyTabs() {
return (
<Stack.Navigator
initialRouteName="Home">        
<Stack.Screen name="Home" component= {Home} options={{headerShown: false}}/>
<Stack.Screen name="Screen1" component= {ListHome} options={{headerShown: false}}/> 
<Stack.Screen name="Screen2" component= {MapHome} options={{headerShown: false}}/>
</Stack.Navigator>
);
}

export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
initialRouteName="Home"
screenOptions={{
tabBarActiveTintColor: '#F60081',
tabBarInactiveTintColor: '#4d4d4d',
tabBarStyle: {
backgroundColor: '#d1cfcf',
borderTopColor: 'transparent',
},
}} 
>
<Tab.Screen
name="Home"
component={MyTabs}
options={{
tabBarLabel: 'Home',
headerShown: false,
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Screen3"
component={Screen3}
options={{
tabBarLabel: 'Screen3',
headerShown: false,
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account-group" color={color} size={size} />
),
}}
/>

</Tab.Navigator>
</NavigationContainer>
);
}

Home.js

const [isVisile, setIsVisible] = React.useState(true);
const [whichComponentToShow, setComponentToShow] = React.useState("Screen1");

React.useEffect(() => {
if(route.params && route.params?.componentToShow) {
setComponentToShow(route.params?.componentToShow);
goToMap()
}
}, [route.params]);

const goToMap = () => {
setComponentToShow("Screen2");
}
const goToList = () => {
setComponentToShow("Screen1");
}
return(
<View style={{backgroundColor: '#d1cfcf' ,flex: 1}}>
{whichComponentToShow === 'Screen1' && <ListHome />}
{whichComponentToShow === 'Screen2' && <MapHome />}
<View style={{position: 'absolute', top: 0, left: 0, right: 1}}>
<Top3
renderMap={goToMap}
renderList={goToList}
active={route.params && route.params?.componentToShow==='Screen2'|| false}
/> 
</View>
</View>
);
}
export default Home;

slider.js 的顶部


const [active, setActive] = useState(false)
let transformX = useRef(new Animated.Value(0)).current;
useFocusEffect( React.useCallback(()=>{
setActive(Boolean(props.active))
console.log(props.active)
},[props.active]))

问题是screen.js文件上的useFocuseEffect

...
useFocusEffect(
React.useCallback(() => {
setActive(Boolean(props.active));
console.log('focus effect running:', props.active);
}, [props.active])
);
...

每当screen.js挂载时,就会调用此效果。

删除此项后,除单击Screen3文本时切换滑块外,其他一切都如预期一样工作。原因是只有在道具参数更改时才计算active道具。为了解决这个问题,我们可以

  1. active的状态移动到负责检测参数变化的Home.js

  2. 每当params发生变化时,设置值active

  3. 使用此状态值而不是计算道具。

const Home = ({ route }) => {
const [isVisible, setIsVisible] = React.useState(true);
const [whichComponentToShow, setComponentToShow] = React.useState("Screen1");
const [active, setActive] = React.useState(false); // 1.


React.useEffect(() => {
if(route.params && route.params?.componentToShow) {
setComponentToShow(route.params?.componentToShow);
// 2.
if (route.params?.componentToShow === 'Screen2') {
setActive(true);
}
// goToMap()
}
}, [route.params]);

const goToMap = () => {
setActive(true);
setComponentToShow("Screen2");
}
const goToList = () => {
setActive(false);
setComponentToShow("Screen1");
}
return(
<View style={{backgroundColor: '#d1cfcf' ,flex: 1}}>
{whichComponentToShow === 'Screen1' && <ListHome />}
{whichComponentToShow === 'Screen2' && <MapHome />}
<View style={{position: 'absolute', top: 0, left: 0, right: 1}}>
<Top3
renderMap={goToMap}
renderList={goToList}
active={active} 
/> 
</View>
</View>
);
}

这是一份工作零食。https://snack.expo.dev/0DqR-KweY

相关内容

最新更新