Redux不适用于React Native(不变违规)

时间:2019-11-11 18:18:56

标签: reactjs native

错误消息:

https://imgur.com/LBNyl2M

App.js

import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Provider } from 'react-redux';
import Layout from './containers/Layout/Layout';

import store from './store/index';

export default function App() {

    return (

      <Provider store={store}><Layout/></Provider>

    );

}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

index.js

import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(reducer);

export default store;

reducer.js

import * as actionTypes from './actions';
import moment from 'moment';

const initialState = {

    itemList: [],
    idCount: 0,
    text: 'Write your to do item!',
    chosenDate: 'no-date',
    activeItems: 0,
    completedItems: 0,
    showCompletedList: false

}

const reducer = (state = initialState, action) => {

    switch(action.type){

        case actionTypes.ADDTOLIST:

            const objItem = { 'id': state.idCount+1, 'text': state.text, 'date': state.chosenDate, 'completed': false, 'displayTextInput': false, 'pickerVisible': false };
            return {
                ...state, 
                itemList: [...state.itemList, objItem],
                idCount: state.idCount+1,
                activeItems: state.activeItems+1
            }

        case actionTypes.REMOVEFROMLIST:

            let oldItemList = [...state.itemList];
            let index = oldItemList.indexOf(action.item);

            if( index !== -1) oldItemList.splice(index, 1);

            return {
                ...state,
                itemList: [...oldItemList],
                activeItems: action.item.completed ?  state.activeItems : state.activeItems-1,
                completedItems: action.item.completed ?  state.completedItems-1 : state.completedItems
            }

        case actionTypes.EDITITEMDATE:

            oldItemList = [...state.itemList];
            index = oldItemList.indexOf(action.item);

            if(index !== -1){
                oldItemList[index].date = state.chosenDate;
                return {
                    ...state,
                    itemList: [...oldItemList]
                }
            }

            return state;

        case actionTypes.EDITITEMSTATUS:

            oldItemList = [...state.itemList];
            index = oldItemList.indexOf(action.item);

            if(index !== -1){
                oldItemList[index].completed = !oldItemList[index].completed;
                return {
                    ...state,
                    itemList: [...oldItemList],
                    activeItems: action.item.completed ?  state.activeItems+1 : state.activeItems-1,
                    completedItems: action.item.completed ?  state.completedItems-1 : state.completedItems+1
                }
            }

            return state;

        case actionTypes.EDITITEMTEXT:

            oldItemList = [...state.itemList];
            index = oldItemList.indexOf(action.item);

            if(index !== -1){
                oldItemList[index] = state.text;
                return {
                    ...state,
                    itemList: [...oldItemList]
                }
            }

            return state;

        case actionTypes.TOGGLETEXTINPUT:

            oldItemList = [...oldItemList];
            index = oldItemList[index].indexOf(action.item);

            if(index !== -1){
                oldItemList[index],displayTextInput = !oldItemList[index],displayTextInput;
                return {
                    ...state,
                    itemList: [...oldItemList]
                }
            }

            return state;

        case actionTypes.FILTERACTIVEITEMS:
            return {
                ...state,
                showCompletedList: false
            }

        case actionTypes.FILTERCOMPLETEDITEMS:
            return {
                ...state,
                showCompletedList: true
            }

        case actionTypes.HANDLECHANGETEXT:
            return {
                ...state,
                text: action.text
            }

        case actionTypes.HIDEPICKERINITEM:

            oldItemList = [...state.itemList];
            index = oldItemList[index].indexOf(item);

            if(index !== -1){
                oldItemList[index].isVisible = false;
                return {
                    ...state,
                    itemList: [...oldItemList]
                }
            }

        case actionTypes.SHOWPICKERINITEM:

                oldItemList = [...state.itemList];
                index = oldItemList[index].indexOf(item);

                if(index !== -1){
                    oldItemList[index].isVisible = true;
                    return {
                        ...state,
                        itemList: [...oldItemList]
                    }
                }

                return state;

        case actionTypes.HANDLEPICKER:

            return{
                ...state,
                chosenDate: moment(action.datetime).format('MMM, Do YYYY HH:mm') 
            }

    }

}

export default reducer;

Layout.js

import React, { Component } from 'react';
import { Button, KeyboardAvoidingView } from 'react-native';
import AddScreen from '../../components/AddScreen/AddScreen';
import TodoList from '../../components/TodoList/TodoList';
import Header from '../../components/UI/Header/Header';

class Layout extends Component {

    state = {

        displayItems: false,
        pickerVisible: false

    }

    toggleItems = () => {
        this.setState({ displayItems: !this.state.displayItems });
    }

    showPicker = () => {
        this.setState({ pickerVisible: true });
    }

    hidePicker = () => {
        this.setState({ pickerVisible: false });
    }

    render () {

        let childComponent = <AddScreen 
                                toggleItems={this.props.toggleItems}
                                showPicker={this.props.showPicker}
                                hidePicker={this.props.hidePicker}
                                pickerVisible={this.props.pickerVisible}

                                />;

        if(this.props.displayItems){

            childComponent = <TodoList 
                                itemList={this.state.itemList} 
                                showCompletedList={this.state.showCompletedList}

                                />;

        }

        return (
           <KeyboardAvoidingView style={{flex:1}} behavior="padding">

                <Header />

                {childComponent}

                <Button title='Toggle Items' onPress={this.toggleItems} /> 

           </KeyboardAvoidingView>
        );
    }

}

export default Layout;

我在github上的完整项目: https://github.com/rvmelo/todolist-redux

是代码错误还是与软件包更新有关?

我收到以下错误:“ 不变违反:元素类型无效:预期为字符串(对于内置组件)或类/函数(对于复合组件),但得到:未定义。您可能忘记了从其定义的文件中导出您的组件,否则您可能混淆了默认命名导入。

1 个答案:

答案 0 :(得分:0)

您将不得不进行最后的跟踪。当您尝试渲染不存在的组件(或在您告诉它的路径中不存在)时,通常会出现该错误,如果无法访问大多数项目,这是无法分辨的。

AddScreenTodoListHeader中确保它们全部为export default。如果它们呈现了任何外部组件,则如果以相同的方式导入,则需要对其进行检查。

一种调试方法是一次删除每个组件,然后查看哪个组件损坏了。

-------更新---------

查看您在GitHub上的项目,我发现其中两个组件被命名为export。

Layout更改为以下内容:

import { AddScreen } from '../../components/AddScreen/AddScreen';
import { TodoList } from '../../components/TodoList/TodoList';

说明

执行export myFunction时,将其导出为 。因此,您必须使用命名的导入语法将其导入,如下所示:

import { myFunction } from '..'

当您执行export default myFunction时,它是默认值导出并且可以导入为任何东西,因此您不必使用花括号,而是这样做:

import Anything from '...' //path to myFunction