减速器功能更改状态,但屏幕未重新渲染

时间:2020-09-20 18:27:17

标签: javascript react-native

在使用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.js main.js App.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"
}

2 个答案:

答案 0 :(得分:4)

您需要克隆该数组,然后对其进行修改,然后尝试对原始数组进行突变。

请参见.pop().slice()的文档:

slice()方法将数组的一部分的浅表副本返回到从头到尾(不包括end)选择的新数组对象中,其中start和end表示该数组中项的索引。原始数组将不会被修改。

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

因此,基本上,这就是.slice()有效而.pop()在这种情况下无效的原因。

答案 1 :(得分:1)

前者不起作用,因为您正在对数组进行变异。

请考虑以下片段:

const bla = {
  key: [1, 2]
};

let {
  key
} = bla;

key.pop();

console.log(key);
console.log(bla);

const bla = {
  key: [1, 2]
};
let {
  key
} = bla;

console.log(key.slice(0, key.length - 1));
console.log(bla)

请注意,console.log(bla)会在pop修改数组时记录不同的值,而slice会创建一个新数组。