在LisPage.js中,当组件在调用showCardDetails((后加载其未定义的给定props.detail时。在logger中,它被明确地调用了,但不明白为什么它显示为未定义。我尝试了setTimeout((,但结果还是一样。即使showCardDetail((也能正确地控制台.log(card(,但有效负载仍然返回未定义的值。
store.js
import { createStore, applyMiddleware } from 'redux'
import counter from '../redux/action';
import thunk from 'redux-thunk';
import {reducer} from './reducer';
import logger from 'redux-logger';
import {composeWithDevTools} from 'redux-devtools-extension/developmentOnly';
const middleware = [thunk]
// const logger = createLogger({
// /* https://github.com/evgenyrodionov/redux-logger */
// collapsed: true,
// diff: true
// });
export const store = createStore(
reducer,
composeWithDevTools(
/* logger must be the last middleware in chain to log actions */
applyMiddleware(thunk, logger)
)
)
reducer.js
import data from '../data.json';
import {showCard} from './dispatchAction';
const initialState = {
value:data,
filterValue:[],
detail:[]
}
export const reducer = (state = initialState, action) => {
switch (action.type){
case 'SHOW_DATA':
return {
value: action.payload
}
case 'SHOW_CARD':
return [
state.detail = action.payload
]
}
return state
}
dispatchAction.js
import data from '../data.json';
export const showDATA = () => dispatch => {
dispatch({type:'SHOW_DATA', payload:data})
}
export const showCardDetail = (id) => async dispatch => {
// let card = {}
// data.map((d, i) => {
// if (d.id === id){
// console.log('data from red', d);
// card = d;
// }
// });
const card = data.filter(d => d.id === id)
console.log(card);
await dispatch({type:'SHOW_CARD', payload:card})
};
ListPage.js
/* eslint-disable prettier/prettier */
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable prettier/prettier */
import React, {useState, useEffect} from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {connect} from 'react-redux';
import { showCardDetail, showDATA } from '../../../redux/dispatchAction';
import show from '../../../redux/action';
import {
View,
Text,
SafeAreaView,
ScrollView,
TouchableOpacity,
Modal,
Alert,
Pressable,
} from 'react-native';
import WareCard from '../../components/WareCard/WareCard';
import styles from './styles';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import DropDownPicker from 'react-native-dropdown-picker';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
const arr = [1, 1, 1, 1, 1, 1, 1, 1, 1];
function ListPage(props) {
const {navigation, value} = props;
const [modalVisible, setModalVisible] = useState(false);
const [showContent, setShowContent] = useState();
useEffect(() => {
// console.log(showData);
setShowContent(value && value !== undefined ? value : '');
// console.log(value)
props.showCardDetail(2)
props.showDATA();
// setTimeout(() => {
// console.log("%% ",props.detail, "$$$$$$$$");
// }, 2000)
console.log(": ",props.detail, "$$$$$$$$");
}, []);
function spaceFilter(){
let sd = []
value.map((da, index) => {
if (da.is_live === true){
sd.push(da);
}
setShowContent(sd)
setModalVisible(!modalVisible)
})
}
function registerFilter(){
let sd = []
value.map((da, index) => {
if (da.is_registered === true){
sd.push(da);
}
setShowContent(sd)
setModalVisible(!modalVisible)
})
}
return (
<SafeAreaView style={styles.page}>
<View style={styles.header}>
<Text style={styles.title}>Warehouses</Text>
<TouchableOpacity onPress={() => setModalVisible(!modalVisible)}>
<MaterialIcon name="filter-alt" style={styles.filter}></MaterialIcon>
</TouchableOpacity>
</View>
<Modal
animationType="fade"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<TouchableOpacity onPress={() => spaceFilter()}>
<Text style={styles.modalText}>Space available</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => registerFilter()}>
<Text style={styles.modalText}>Registered</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
<ScrollView
contentContainerStyle={styles.scrollPage}
showsVerticalScrollIndicator={false}>
{showContent && showContent !== undefined ?
showContent.map((data, index) => {
return (
<WareCard
city={data.city}
cluster={data.cluster}
name={data.name}
space_available={data.space_available}
type={data.type}
is_live={data.is_live}
navigation={navigation}
is_registered={data.is_registered}
code={data.code}
key={index}
/>
);
})
:
null
}
</ScrollView>
</SafeAreaView>
);
}
function mapStateToProps(state){
return {
value: state.value,
detail: state.detail,
filterValue:state.filterValue,
}
}
export default connect(mapStateToProps, {
showDATA,
showCardDetail
})(ListPage);
App.js
/* eslint-disable prettier/prettier */
import React from 'react';
import ListPage from './src/screens/ListPage/ListPage';
import DetailPage from './src/screens/DetailPage/DetailPage';
import EditPage from './src/screens/EditPage/EditPage';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import { Provider } from 'react-redux';
import {store} from './redux/store';
function App() {
const Stack = createNativeStackNavigator();
return (
<>
{/* <ListPage /> */}
<Provider store={store}>
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name="List" component={ListPage} />
<Stack.Screen name="Detail" component={DetailPage} />
<Stack.Screen name="Edit" component={EditPage} />
</Stack.Navigator>
</NavigationContainer>
</Provider>
</>
);
}
export default App;
您的减速器错误。
它需要始终返回完整的状态值,包括正在更新的任何字段、和未更新的字段。
这两种情况都被打破了:
switch (action.type){
case 'SHOW_DATA':
return {
value: action.payload
}
case 'SHOW_CARD':
return [
state.detail = action.payload
]
}
第一个确实返回一个对象,但只返回一个名为value
的字段。因此,在调度该操作之后,您将完全丢失state.detail
和state.filterValue
。
第二种情况更为糟糕:
- 它返回的是一个对象而不是数组
- 它试图变异
state.detail =
,而不是进行正确的不可变更新 - 它仍然只更新三个字段中的一个
关于这一点,我还注意到showCardDetail()
动作创建者是通过首先计算整个过滤数组并将其填充到动作中来使用的。这与我们希望人们使用Redux的方式背道而驰。相反,我们建议在减速器中加入尽可能多的逻辑。或者,在过滤的情况下,很多时候你甚至不应该在reducer中执行该逻辑——而是在渲染或选择器中执行过滤。
这里最大的解决方案是我强烈建议您切换到使用我们的官方Redux Toolkit包编写Redux逻辑。它将极大地简化您的代码,发现常见错误,并使所有这些变得更加容易。例如,使用RTK,可以将整个减速器写成:
const dataSlice = createSlice({
name: 'data',
initialState,
reducers: {
dataUpdated(state, action) {
state.value = action.payload;
}
cardShown(state, action) {
// You can filter here, so I'm showing this, but really do filtering
// in a selector instead
state.detail = state.detail.filter(d => d.id === action.payload.id)
}
}
})