Array menjadi tidak terdefinisi - React Redux

saya baru mengenal React dan Redux. Mencoba memahami dasar-dasarnya dan melakukan beberapa contoh sederhana, tetapi saya terjebak dalam masalah ini selama lebih dari satu hari dan saya tidak dapat menemukan solusinya. Saya membayangkan bahwa kesalahan saya adalah kesalahan bodoh.

Masalahnya adalah saya tidak dapat mencetak berbagai pengguna. Saat melakukan debug, variabel pengguna dimuat dengan semua id dan pengguna yang diperbaiki, namun setelah menjalankan <li key={id}>{name}</li> sebanyak tiga kali, variabel tersebut kembali ke forEach dan memberi saya pengecualian ini: TypeError Tidak Tertangkap: Tidak dapat membaca properti 'forEach' yang tidak ditentukan, dengan pengguna tidak ditentukan. Dan saya juga mendapatkan kesalahan terkait dengan PropTypes: Pengguna prop tidak valid dari tipe array yang disediakan ke HomePage, objek yang diharapkan

Ini kodenya:

toko/configureStore.js

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/index';

const initialState = {};

const middleware = [thunk];

const store = createStore(rootReducer, initialState, compose(
    applyMiddleware(...middleware),
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
));

export default store;

pengurang/index.js

import { combineReducers } from 'redux';
import userReducer from './userReducer';
//import groupReducer from './groupReducer';

export default combineReducers({
    user: userReducer
});

pengurang/penggunaReducer.js

import { GET_USERS, ADD_USER, DELETE_USER } from '../actions/types';

const initialState = {
    users: [
        { id: 1, name: 'brunao'},
        { id: 2, name: 'flavio'},
        { id: 3, name: 'dudu'}
    ]
};

export default function(state = initialState, action) { 
    switch (action.type) {
        case GET_USERS:
            return [
                ...state
            ];
        default:
            return state;
    }
}

aksi/penggunaAction.js

import { GET_USERS, ADD_USER, DELETE_USER } from './types';

export const getUsers = () => {
    return {
        type: GET_USERS
    };
};

komponen/HomePage.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getUsers } from '../actions/usersActions';
import PropTypes from 'prop-types';

class HomePage extends Component {

    componentDidMount() {
        this.props.getUsers();
    }

    render() {
        const { users } = this.props.user;
        return(
            <div>
                <h3>Users</h3>
                <ul>
                    {users.forEach(({id, name}) => (
                        <li key={id}>{name}</li>
                    ))}
                </ul>
            </div>
        );
    }

}

HomePage.propTypes = {
    getUsers: PropTypes.func.isRequired,
    user: PropTypes.object.isRequired
}

const mapStateToProps = (state) => ({
    user: state.user
});

export default connect(mapStateToProps, { getUsers })(HomePage);

person Bruno Paiva    schedule 21.07.2018    source sumber


Jawaban (2)


Anda mengembalikan bentuk keadaan yang salah pada peredam Anda. Kode terkait Anda:

export default function(state = initialState, action) { 
    switch (action.type) {
        case GET_USERS:
            return [
                ...state
            ];
        default:
            return state;
    }
}

Di sini, status adalah sebuah objek tetapi Anda mengembalikannya dalam array dengan menyebarkannya. Jadi, keadaanmu menjadi rusak.

Cobalah seperti itu:

case GET_USERS:
    return state;

Seperti yang ditunjukkan oleh @Idan Dagan dalam jawabannya, sebenarnya kami tidak mengubah status di reduksi kami. Saya hanya memberikan saran ini karena Anda hanya bermain-main mempelajari Redux dan kami mengembalikan keadaan semula di sini, tidak lebih. Namun, ini adalah cara yang cocok dan lebih baik untuk mengembalikan keadaan:

case GET_USERS:
    return { ...state };

Berikut ini kode yang berfungsi: https://codesandbox.io/s/k5ymxwknpv

Saya juga mengganti forEach dengan map lagi seperti yang disarankan @Idan Dagan. Aku belum menyadarinya. forEach bukan metode yang cocok di sini karena sebenarnya tidak mengembalikan apa pun. Anda ingin memetakan array Anda di React dan merendernya.

Selain itu, nama negara bagian Anda membingungkan :) user.users agak aneh, mungkin Anda bisa memikirkan nama yang lebih baik.

Edit setelah komentar

Tindakan GET_USERS Anda sebenarnya sedang terkena, tetapi Anda salah memeriksanya di kode Anda. Anda sedang melakukan:

export default function(state = initialState, action) {
  switch (action.type) {
    case GET_USERS:
      return Object.assign({}, state);
    default:
      return {
        users: [
          { id: 1, name: "TEST" },
          { id: 2, name: "TEST1" },
          { id: 3, name: "TEST2" }
        ]
      };
  }
}

Apa yang terjadi di sini? Tindakan pertama Redux adalah INIT. Ini adalah inisialisasi status Anda. Sekarang, karena tidak ada tindakan tertentu, peredam Anda akan menggunakan case default dan mengembalikan yang TEST. Sekarang, negara bagian Anda menjadi data UJI ini. Kemudian GET_USERS Anda dipukul dan Anda mengembalikan objek baru yang menggabungkan status yang merupakan TEST. Berikut langkah-langkahnya:

First, state is the `initialState` -> `INIT` runs and hits the default case
State is now TEST one -> GET_USERS hit and returns the `state` which is TEST one
You see the TEST one.

Bagaimana Anda bisa menguji tindakan Anda? Masukkan saja console.log ke dalam peredam Anda:

export default function(state = initialState, action) {
  console.log("state",state);
  console.log("action",action);
  .....

dan lihat GET_USERS sebenarnya sedang diserang. Pilihan lainnya adalah daripada mengembalikan objek yang digabungkan dengan state, coba gabungkan dengan initialState atau dengan operator spread kembalikan objek baru dengan menggunakan initialState:

return return Object.assign({}, initialState);

or

return {...initialState}

Opsi terakhir memberi Anda sedikit lebih banyak pemahaman tentang cara kerja penjelasan pertama saya. Coba kembalikan ini untuk GET_USERS Anda:

return {...state, users:[...state.users, {id:4, name: "foo"}]};

Anda akan melihat daftar pengguna dengan data TEST tetapi yang terakhir adalah foo Anda. Ini menjelaskan bagaimana Anda kehilangan initialState jika Anda mengembalikan apa pun selain state dalam kasus default Anda.

Saran terakhir, Anda dapat men-debug pengembangan Redux Anda dengan Redux Dev Tools. Ini adalah alat yang hebat dan melakukan lebih dari sekadar debugging. Anda dapat dengan mudah melacak semua operasi Anda untuk Redux.

person devserkan    schedule 21.07.2018
comment
Ya, koreksi di dalam return ini menghentikan kesalahan, sekarang saya mendapatkan penggunanya. Tetapi saya melakukan tes dan saya mendapatkan pengguna karena opsi default di dalam switch, saya tidak mengirimkan tindakan GET_USERS.. Saya mencoba mengubah ComponentDidMount() menjadi ComponentWillMount() tetapi tidak berhasil - person Bruno Paiva; 21.07.2018
comment
@BrunoPaiva ComponentWillMount dianggap warisan dan Anda harus menghindarinya. - person Idan Dagan; 21.07.2018
comment
DidMount atau WillMount tidak berpengaruh apa pun dalam hal ini. Dan seperti yang diceritakan, WillMount sudah menjadi warisan sekarang. Bagaimana Anda melacak tindakan Anda? Apakah Anda yakin itu tidak kena? Bisakah kami melihat file types Anda? Selain itu, bisakah Anda meletakkan seluruh aplikasi Anda ke codesandbox.io sehingga kami dapat memeriksanya. - person devserkan; 21.07.2018
comment
Saya telah mengedit jawaban saya dan menambahkan contoh kode dan kotak yang berfungsi. Juga, saya telah mengubah forEach dengan map sesuai dengan saran @IdanDagan. Tangkapan yang bagus! - person devserkan; 21.07.2018
comment
codesandbox.io/s/my6k6o037p Ini kodenya.. saya mengubah pengembalian default di dalam saklar dan konfirmasikan bahwa tindakan GET_USERS tidak dipanggil.. Dan terima kasih atas bantuan Anda berdua!! Sangat menghargai! - person Bruno Paiva; 22.07.2018
comment
Saya telah mengedit jawaban saya dan mencoba menjelaskan bagaimana sebenarnya GET_USERS Anda terkena. - person devserkan; 22.07.2018
comment
@devserkan lebih baik melakukan debug tindakan melalui Redux DevTool untuk chrome. Bagaimanapun, saya memberi Anda upvoting :). - person Idan Dagan; 22.07.2018
comment
@IdanDagan, saya setuju sepenuhnya dengan Anda. Saya menggunakan Redux Dev Tools setiap kali saya menggunakan Redux, itu adalah alat yang hebat. Di sini, saya hanya ingin menunjukkan cara sederhana karena OP sedang mencoba men-debug masalah di peredam. Bagaimanapun, saya telah mengedit jawaban saya dan menyebutkan dari Redux Dev Tools. Terima kasih. - person devserkan; 22.07.2018
comment
Terima kasih teman-teman atas pelajaran luar biasa ini :) Saya tidak tahu tindakan INIT dipanggil terlebih dahulu! Sekarang redux lebih jelas bagi saya.. Sekali lagi, terima kasih dan semoga harimu menyenangkan. - person Bruno Paiva; 22.07.2018

Saya tidak yakin apa yang Anda coba lakukan dengan negara bagian baru ini.

Namun ada beberapa perubahan yang perlu Anda lakukan:

  1. Gunakan map daripada forEach (karena Anda ingin mengembalikan array baru).
  2. Di peredam Anda dapat mengembalikan keadaan seperti ini:

export default function(state = initialState, action) { 
    switch (action.type) {
        case GET_USERS:
            return Object.assign({}, state);
        default:
            return state;
    }
}

seperti yang disebutkan dalam dokumen redux:

Kami tidak mengubah keadaan. Kami membuat salinan dengan Object.assign().

person Idan Dagan    schedule 21.07.2018
comment
Terima kasih @Idan atas bantuannya. Seperti yang saya komentari di atas, masih belum memanggil tindakan GET_USERS.. - person Bruno Paiva; 22.07.2018