首页 > 解决方案 > 减速器功能改变状态,但屏幕不重新渲染

问题描述

在我使用 Android Studio 设置的 React Native 应用程序中,我使用 redux-persist 来持久化状态,存储引擎是 AsyncStorage。在应用程序中,我有一个“添加”按钮和一个“删除”按钮,用于从状态中添加和删除项目。

“添加”按钮工作正常,它将一个项目添加到状态并重新渲染屏幕。但是“删除”按钮虽然从状态中删除了一个项目(我在 React Native Debugger 上看到过),但它不会重新渲染屏幕并保持状态。但是不同版本的代码可以工作。

我想知道为什么以前的版本不起作用。这是我的减速器功能:

//reducer.js

import React from 'react';

const initialState = {
    key: [
        { id: 0 },
        { id: 1 }
    ]
};

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

    switch (action.type) {
        case 'SAVE':
            return { key: [...state.key, action.payload] };

        // this version doesn't re-render the screen and doesn't persist
        case 'REMOVE':
            let { key } = state;
            key.pop();
            return { key };
        
        // this version re-renders the screen and persists
        case 'REMOVE':
            let { key } = state;
            return { key : key.slice(0, key.length - 1)};

        default:
            return state;
    }
};

export { reducer };

这是我的store.jsmain.jsApp.js和依赖项:

// store.js

import React from 'react';
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-community/async-storage';
import { reducer } from './reducer';

const persistConfig = {
    key: 'abc',
    storage: AsyncStorage
};

const pReducer = persistReducer(persistConfig, reducer);

let store = createStore(
    pReducer,
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

let persistor = persistStore(store);

export { store, persistor };


// main.js

import React, { useState } from 'react';
import { ScrollView, View, Text, Button } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';

const Main = () => {

    let key = useSelector(state => state.key);
    const dispatch = useDispatch();

    const [show, setShow] = useState(false);

    const add = () => {
        dispatch({ type: "SAVE", payload: { id: key.length } });
    }

    const remove = () => {
        dispatch({ type: "REMOVE" });
    }

    const load = () => {
        setShow(true);
    }

    const items = key.map((item) => <Text key={item.id}>{item.id}</Text>);

    return (
        <ScrollView>
            <View>
                <Button
                    title='add'
                    onPress={add}
                />
                <Button
                    title='remove'
                    onPress={remove}
                />
                <Button
                    title='load'
                    onPress={load}
                />
                {show ? <Text>your state contains {key.length} items</Text> : <Text></Text>}
            </View>
            <View>
                {items}
            </View>
        </ScrollView>
    );
};

export default Main;


// App.js

import React from 'react';
import { Provider } from 'react-redux';
import { store, persistor } from './store';
import { PersistGate } from 'redux-persist/integration/react';
import Main from './main';

const App = () => {

  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
      <Main/>
      </PersistGate>
    </Provider>
  );
};

export default App;


//package.json

"dependencies": {
    "@react-native-community/async-storage": "^1.12.0",
    "@react-native-community/masked-view": "^0.1.10",
    "@react-navigation/native": "^5.7.3",
    "@react-navigation/stack": "^5.9.0",
    "react": "16.13.1",
    "react-native": "0.63.2",
    "react-native-gesture-handler": "^1.8.0",
    "react-native-reanimated": "^1.13.0",
    "react-native-safe-area-context": "^3.1.8",
    "react-native-screens": "^2.11.0",
    "react-redux": "^7.2.1",
    "redux": "^4.0.5",
    "redux-persist": "^6.0.0"
},
"devDependencies": {
    "@babel/core": "^7.8.4",
    "@babel/runtime": "^7.8.4",
    "@react-native-community/eslint-config": "^1.1.0",
    "babel-jest": "^25.1.0",
    "eslint": "^6.5.1",
    "jest": "^25.1.0",
    "metro-react-native-babel-preset": "^0.59.0",
    "react-test-renderer": "16.13.1"
}

标签: javascriptreact-native

解决方案


您需要克隆该数组然后修改它,您试图改变原始数组。

.pop()从和的文档中查看.slice()

slice() 方法将数组的一部分的浅拷贝返回到从开始到结束(不包括结束)选择的新数组对象中,其中开始和结束表示该数组中项目的索引。原始数组不会被修改。

pop 方法从数组中删除最后一个元素并将该值返回给调用者。

所以基本上这就是为什么在这种情况下.slice()有效而无效的原因。.pop()


推荐阅读