React & Redux: невозможно прочитать свойство undefined

Я пытаюсь написать приложение в React, и я столкнулся с проблемой управления состоянием для очень многих компонентов, поэтому я хотел использовать redux. Из того, что я прочитал, Redux не работает с корневым компонентом, поэтому я создал промежуточный компонент, назвав его «оболочкой», который будет обертывать все и управлять состоянием моего приложения. Итак, теперь у меня есть исходный корневой компонент и компонент-оболочка. Я пытаюсь получить некоторые реквизиты в этом компоненте-оболочке с помощью redux, но реквизиты по какой-то причине не заполнены, и я не могу это понять.

Вот мой код:

import * as React from 'react'
import { Provider } from "react-redux";
import { connect } from "react-redux";
//SPFX references
import { DefaultButton, IButtonProps } from 'office-ui-fabric-react/lib/Button';
import { Panel, PanelType } from 'office-ui-fabric-react/lib/Panel';

//custom references
import { IRootProps } from '../props/IRootProps'
import { IRootState } from '../states/IRootState'
import { ITile, ITileHeader, ITileItem } from '../props/ITileStructure'
import store from '../main/store'
import { openPanel, closePanel } from '../actions/panelAction'

//Styles references
import rootStyles from '../styles/RooComponent.module.scss'
import commonStyles from '../styles/common.module.scss'

//Components references
import PanelComponent from './PanelComponent'
import FooterComponent from './FooterComponent'
import DiscardChangesDialogComponent from './DiscardChangesDialogComponent'
import BladesRootComponent from './BladesRootComponent'
import TilesListComponent from './TilesListComponent'

class RootComponent extends React.Component<{}, {}>{
    tiles: ITile[] = [];

    constructor(props) {
        super(props);
    }

    render(): JSX.Element {
        return (
            <Provider store = {store}>
                <AppWrapper />
            </Provider>

        )
    }
}

class AppWrapper extends React.Component<IRootProps, IRootState>{
    tiles: ITile[] = [];

    constructor(props: IRootProps) {
        super(props);

        if (this.tiles.length === 0) {
            for (let i = 0; i < 200; i++) {
                this.tiles.push({
                    key: i,
                    tileName: 'tile ' + i,
                    tileImageUrl: 'image url ' + i,
                    tileOrder: i,
                    headers: []
                });
            }
        }
    }
    render(): JSX.Element {
        return (
            <div className = "RootComponent">
                <DefaultButton onClick = {() => this.props.panelProps.openPanel()} className = {commonStyles.defaultButton} >Configure Tiles</DefaultButton>
                <Panel
                    isOpen = {this.props.panelProps.isPanelOpen}
                    // tslint:disable-next-line:jsx-no-lambda
                    onDismiss = {() => {
                        this.setState({ showPanel: false })
                    }}
                    type = {PanelType.extraLarge}
                    headerText = "Tiles configuration"
                    hasCloseButton = {false}>
                    <PanelComponent />
                </Panel>
            </div>
        )
    }
}

let mapStateToProps = (state) => {
    return {
        panelProps: state.panel,
    };
};

let mapDispatchToProps = (dispatch) => {
    return {
        openPanel: () => {
            dispatch(openPanel());
        }
    };
};

connect(mapStateToProps, mapDispatchToProps)(AppWrapper);
export default RootComponent; 

Это код для ../main/store:

import {createStore, combineReducers} from 'redux';
import {Store} from 'redux';

import panel from "../reducers/panelReducer";
let store =  createStore(
    combineReducers({
        panel
    }),
    {}
);

export default store; 

и ../reducers/panelReduce выглядит так:

//(state, action) => 
const panelReducer = (state = {
    isPanelOpen: false
}, action) => {
    switch (action.type) {
        case "OPEN_PANEL":
            state = {
                ...state,
                isPanelOpen: true
            };
            break;
        case "CLOSE_PANEL":
            state = {
                ...state,
                isPanelOpen: false
            };
            break;
    }
    return state;
};

export default panelReducer;

Однако код выполняется, и в строке: <Panel isOpen = {this.props.panelProps.isPanelOpen} он сообщает мне, что не может получить доступ к isPanelOpen из undefined. По какой-то причине Redux подключен неправильно.

P.S Я все еще новичок в Redux, поэтому могу делать что-то не так, если кто-то может указать мне правильное направление.

это должно быть this.props.isPanelOpen, поскольку нет свойств с именем panelProps

CRayen 10.09.2018 19:47

Привет, CRayen, но я хочу объединить несколько редукторов. В моем файле магазина я разрешил `` store = createStore (combReducers ({``, чтобы не было другого объекта между props и .isPanelOpen? .. Также, когда я регистрирую this.props, он дает мне это {}

DMZ 10.09.2018 19:50

вы пробовали let store = createStore(combineReducers({panel})); вместо let store = createStore(combineReducers({panel}), {});? Обычно вы устанавливаете начальное состояние на {}, поэтому он не будет работать ...

Olivier Boissé 10.09.2018 19:52

@CRayen panelProps определен в функции mapStateToProps, поэтому this.props.panelProps.isPanelOpen верен

Olivier Boissé 10.09.2018 19:53

@CRayen Я пробовал вот так let store = createStore (combReducers ({panel})); .. та же ошибка

DMZ 10.09.2018 19:56

@ Оливер Верно. Я скучал. Я также подозреваю, что в mapDispatchToProps openPanel присваивается невозвратное значение.

CRayen 10.09.2018 20:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
6
610
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Фактически, вы не использовали подключенный компонент AppWrapper внутри вашего RootComponent.

Вы можете создать константу AppWrapperConnected: const AppWrapperConnected = connect(mapStateToProps, mapDispatchToProps)(AppWrapper); и использовать <AppWrapperConnected/> внутри RootComponent

Более того, я думаю, будет легче поддерживать, если вы разделите RooComponent и AppWrapper в два отдельных файла.

Еще совет - mapStateToProps переписать вот так

let mapStateToProps = (state) => state.panel

так что вы можете напрямую использовать this.props.isPanelOpen, я думаю, что panelProps здесь бесполезен

Спасибо @Olivier. Но как переназначить AppWrapper .. Только пробовал, говорит не переменная. Поскольку это компонент класса.

DMZ 10.09.2018 20:07

Я отредактировал свой ответ, вы используете let AppWrapper = class extends React.Component... или создаете новую переменную AppWrapperConnected

Olivier Boissé 10.09.2018 20:10

Кстати, а зачем убирать PanelProps из состояния? Что, если у меня есть другое свойство, связанное с чем-то другим с таким же именем?

DMZ 10.09.2018 20:12

Да, но здесь это кажется бесполезным, так как у вас нет другого реквизита с таким же именем ...

Olivier Boissé 10.09.2018 20:12

OK. Спасибо: D

DMZ 10.09.2018 20:13

У меня есть еще один дополнительный вопрос. Теперь работает без ошибок. Однако, когда я нажимаю кнопку, this.props.openPanel () ничего не делает. Я вижу, как выполняется мой код в редукторе, но похоже, что Panel не выбирает новые изменения и не появляется при изменении состояния редукции.

DMZ 10.09.2018 20:51

ваш редуктор неправильный, это должна быть чистая функция redux.js.org/basics/reducers, в основном вы не должны переназначать состояние, вы должны напрямую писать return { ...state, isPanelOpen: true }, и вы можете удалить инструкцию break

Olivier Boissé 10.09.2018 20:54

Ох, хорошо. Спасибо еще раз!

DMZ 10.09.2018 20:59

Другие вопросы по теме