【问题标题】:redux action dispatched successfully but return undefined valueredux 操作已成功分派但返回未定义的值
【发布时间】:2022-01-21 16:20:25
【问题描述】:

在 LisPage.js 中,当组件加载时,它在调用 showCardDetail() 后赋予 props.detail 未定义。在 logger 中明确调用了它,但不明白为什么它显示为未定义。我试过 setTimeout() 但结果还是一样。即使是 showCardDetail() 也可以正常使用 console.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;

【问题讨论】:

    标签: reactjs react-native redux react-redux redux-thunk


    【解决方案1】:

    你的减速器错了。

    它需要总是返回一个完整状态值,包括正在更新的任何字段,的字段没有更新。

    这两种情况都被打破了:

        switch (action.type){
            case 'SHOW_DATA':
                return {
                    value: action.payload
                }
            case 'SHOW_CARD':
                return [
                    state.detail = action.payload
                ]
        }
    

    第一个确实返回一个对象,但只返回一个名为value 的字段。因此,在发送该操作后,您将完全失去 state.detailstate.filterValue

    第二种情况更破:

    • 它返回的是一个对象而不是一个数组
    • 它试图变异 state.detail =,而不是进行正确的不可变更新
    • 它仍然只更新三个字段中的一个

    就此而言,我还注意到 showCardDetail() 动作创建器通过首先计算整个过滤数组并将其填充到动作中来使用。这与我们希望人们使用 Redux 的方式背道而驰。相反,我们推荐putting as much logic as possible in reducers。或者,在过滤的情况下,很多时候你甚至不应该在 reducer 中执行该逻辑 - do filtering while rendering or in a selector instead

    这里最大的修复是我会强烈建议您切换到使用our official Redux Toolkit package 编写您的 Redux 逻辑。它将大大简化您的代码,捕捉常见错误,并使所有这一切变得更加容易。例如,使用 RTK,您可以将整个 reducer 编写为:

    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)
        }
    
      }
    })
    

    【讨论】:

      猜你喜欢
      • 2019-05-17
      • 2018-10-14
      • 2018-09-15
      • 2018-03-27
      • 2018-10-23
      • 2021-04-28
      • 2017-02-01
      • 2015-09-22
      • 1970-01-01
      相关资源
      最近更新 更多