React-Redux - при вызове действия я получаю TypeError: String.prototype.property с нулевым или неопределенным значением - PullRequest
0 голосов
/ 06 апреля 2020

Я пытаюсь реализовать Redux для динамического управления ссылками панели навигации. У меня есть функция «ссылка активна» в ссылках панели навигации, которые активны в зависимости от того, какая страница отображается. По всем ссылкам, которые у меня есть в приложении, которые go на разные страницы, кажется, легче обрабатывать, какая навигационная ссылка активна или нет в магазине Redux.

Я получаю эту ошибку: TypeError: String.prototype.link called on null or undefined когда Я называю одно из моих действий, которое обновляет магазин, какая ссылка должна быть активной.

Вот моя реализация, начинающаяся с моего действия:

navbar_actions. js:

const Types = {
  NAV_LINK_ACTIVE: 'NAV_LINK_ACTIVE',
};

const navlinkActive = (link) => ({
  type: Types.NAV_LINK_ACTIVE,
  payload: link,
});

export default {
  navlinkActive,
  Types,
};

navbar_reducers. js :

import NAVBAR_ACTIONS from '../actions/navbar_actions';
import _ from 'lodash';

const defaultState = {
  link: '',
};

const navbarReducer = (state = defaultState, action) => {
  switch (action.type) {
    case NAVBAR_ACTIONS.Types.NAV_LINK_ACTIVE: {
      let link = action.payload;
      return link;
    }
    default:
      return state;
  }
};

export default navbarReducer;

store. js:

import { createStore } from 'redux';

import navbarReducer from '../reducers/navbar_reducers';

export default function configureStore(initialState) {
  const store = createStore(navbarReducer, initialState);
  return store;
}

Вот мой компонент Links, который Navbar использует для визуализации ссылок (этот компонент просто нужен доступ к состоянию хранилища):

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';

//Redux

import NAVBAR_ACTIONS from '../../../../modules/actions/navbar_actions';
import { connect } from 'react-redux';

import propTypes from 'prop-types';

//Styles
import { LinkContainer, LinkWrap } from './styles';

//Notes
//@Required: links array passed as props. Each object in the links array should contain a path and name property. Refer to propTypes definition at the bottom.

const Links = (props) => {
  const [clickedLink, setClickedLink] = useState('Home');
  useEffect(() => {
    if (props.link.length === 0) return;
    else setClickedLink(props.link);
  }, [props.link]);
  return (
    <LinkContainer>
      {props.links.map((link, i) => (
        <LinkWrap isActive={link.name === clickedLink ? true : false} key={i}>
          <Link
            to={link.path}
            onClick={() => {
              setClickedLink(link.name);
            }}
          >
            {link.name}
          </Link>
        </LinkWrap>
      ))}
    </LinkContainer>
  );
};

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

export default connect(mapStateToProps, null)(Links);

Links.propTypes = {
  links: propTypes.arrayOf(
    propTypes.shape({
      path: propTypes.string.isRequired,
      name: propTypes.string.isRequired,
    })
  ).isRequired,
};

Через useEffect() ловушку, в любое время props.link обновления, он будет обновлять это в состоянии компонента Links. Таким образом, я думаю, что я буду получать обновленную ссылку из состояния store каждый раз, когда она меняется. Возможно, это неправильно, но это моя попытка.

Это компонент, который я называю действием внутри:

import React from 'react';

//Redux
import { connect } from 'react-redux';
import NAVBAR_ACTIONS from '../../../modules/actions/navbar_actions';

import { Link } from 'react-router-dom';

//Styles
import {
  HomePageHero,
  LatestPostsHeader,
  HeroHeader,
  HeroText,
  HeroViewPosts,
} from './styles';

//Components
import Page from '../../Layout/Page';
import Blog from '../Blog/Blog';
import SocialLinks from './Components/SocialMediaLinks/SocialLinks';

const Home = (props) => {
  console.log(props);
  return (
    <Page noheader={true} pageTitle="">
      <HomePageHero>
        <HeroHeader>
          <p>Maison</p>
          <div></div>
          <p>Moa</p>
        </HeroHeader>
        <HeroText>
          <p>
            Loreum Ipsum 
          </p>
        </HeroText>
        <HeroViewPosts>
          <Link
            to="/blog"
            onClick={() => {
              props.navlinkActive('blog');
              console.log(props);
            }}
          >
            View My Blog
          </Link>
        </HeroViewPosts>
        <SocialLinks />
      </HomePageHero>
      <LatestPostsHeader>
        <h3>Latest Posts</h3>
      </LatestPostsHeader>
      <Blog pageTitle="Latest Posts" noheader={true} />
    </Page>
  );
};

const mapDispatchToProps = (dispatch) => ({
  navlinkActive: (link) => dispatch(NAVBAR_ACTIONS.navlinkActive(link)),
});

export default connect(null, mapDispatchToProps)(Home);

Это фактический снимок экрана с ошибкой, которую я получаю при вызове props.navlinkActive():

enter image description here

Я немного растерялся из-за этой ошибки, так как не смог найти ничего, что указано в Redux c относительно этого. Спасибо за помощь и понимание заранее!

1 Ответ

0 голосов
/ 06 апреля 2020

Закончилось решение этой проблемы. Ошибка исходила от моего Links.js компонента:

Конкретно это здесь:

  useEffect(() => {
    if (props.link.length === 0) return;
    else setClickedLink(props.link);
  }, [props.link]);

props.link не определено. Это произошло потому, что я не возвращал состояние хранилища должным образом из navbar_reducer.js.

Вот как редуктор должен был возвращать состояние (используя здесь loda sh cloneDeep()):

const navbarReducer = (state = defaultState, action) => {
  switch (action.type) {
    case NAVBAR_ACTIONS.Types.NAV_LINK_ACTIVE: {
      let link = action.payload;
      let newState = _.cloneDeep(state);
      newState.link = link;
      return newState;
    }
    default:
      return state;
  }
};

Старый путь. Я изменял существующее состояние в редукторе вместо того, чтобы возвращать новую копию состояния с необходимыми изменениями. Я изменял существующее состояние напрямую, и при этом Redux не обнаруживает изменения, поэтому любой компонент, использующий connect() для получения доступа к хранилищу, никогда не получает обновления.

Теперь все работает как положено. Это правило № 1 в React. НЕ МУТАТЬ ГОСУДАРСТВО! Я должен из известных. Убедитесь, что вы всегда получаете подробную копию состояния, а затем вносите изменения в эту копию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...