MapDispatchToProps возвращает функцию - PullRequest
0 голосов
/ 23 мая 2018

Я пытаюсь прочитать мои статьи из базы данных Firebase, но не могу заставить ее работать.

Вот моя БД:

myDB-myid
  articles
    1
     body: "Lorem Ipsum Dolor si damet blablabla"
     createdAt: 12345
     subtitle: "ça promet beaucoup d'autres supers articles"
     title: "Mon premier article"
    2
     body: "Encore du Lorem Ipsum et bla et bla et bla..."
     createdAt: 34567
    subtitle: "Vous avez aimé le premier ? Le deuxième va vous..."
     title: "Et voici le deuxième article"

мой компонент, который должен отображать список всех статей, ArticlePage:

import React from 'react';
import { connect } from 'react-redux';
import Article from './Article';
import { startSetArticles } from '../../actions/articles';

const ArticlesPage = props => (
      <div className="articles-wrapper">
        <div className="container">
        {console.log(props.articles)}
        {
          props.articles.length === 0 ? (
            <p>No article</p>
            ) : (
            props.articles.map(a => {
              return <Article key={a.id} {...a}/>
            })
            )
          }
        </div>
      </div>
      );

const mapDispatchToProps = dispatch => ({
  articles: () => dispatch(startSetArticles())
});

export default connect(undefined, mapDispatchToProps)(ArticlesPage);

мой магазин:

import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import authReducer from '../reducers/auth';
import articlesReducer from '../reducers/articles';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default () => {
  const store = createStore(
    combineReducers({
      auth: authReducer,
      articles: articlesReducer
    }),
    composeEnhancers(applyMiddleware(thunk))
  );

  return store;
};

мои действия в action/articles.js:

import database from '../firebase/firebase';

// SET_ARTICLES
export const setArticles = articles => ({
  type: 'SET_ARTICLES',
  articles
});

export const startSetArticles = () => {
  return dispatch => {
    return database.ref('articles').once('value').then(snapshot => {
      const articles = [];

      snapshot.forEach(a => {
        articles.push({
          id: a.key,
          ...a.val()
        });
      });
      dispatch(setArticles(articles));
    });
  };
};

мой редуктор в reducers/articles.js:

const articlesReducerDefaultState = [];

export default (state = articlesReducerDefaultState, action) => {
  switch (action.type) {
      case 'SET_ARTICLES':
        return action.articles;
    default:
      return state;
  }
};

Но я не могу заставить его работать.Вот консольный вывод console.log(props.articles) от компонента:

ƒ articles() {
      return dispatch((0, _articles.startSetArticles)());
    }

Есть идея?Он должен отображать две записи, но возвращает только саму функцию.(Я получаю «нет статьи» от троичного оператора)

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

articles - это функция, потому что это именно то, что вы делаете:

const mapDispatchToProps = dispatch => ({
  articles: () => dispatch(startSetArticles())
});

вы отображаете диспетчеризацию для реквизита , и вы сопоставляете ее с реквизитом articles, который являетсяфункция, которая отправляет действие.Здесь нет ничего удивительного.Но я думаю, что вы также хотите, чтобы отображал состояние на реквизиты , что вы можете сделать с первым аргументом connect:

const mapStateToProps = state => ({ articlesList: state.articles });
export default connect(mapStateToProps, mapDispatchToProps)(ArticlesPage);

Теперь, если вы сделаете console.log(props), вы должны получить Objectс двумя свойствами:

{
  articles, // a function from mapDispatchToProps
  articlesList // a function from mapStateToProps 
}

РЕДАКТИРОВАТЬ:

Однако вам все равно необходимо вызвать функцию статей для извлечения данных с помощью Firebase и заполнить хранилище избыточности.Лучший способ запустить асинхронные данные - использовать хук componentDidMount ():

class ArticlesPage extends React.Component {
  componentDidMount() {
    this.props.articles();  // use mapped function to dispatch redux action
  }

  render() {
    // render data with array from the store
    return (
      <div className="articles-wrapper">
        <div className="container">
          {this.props.articlesList.length === 0 ? (
            <p>No article</p>
          ) : (
            this.props.articlesList.map(a => {
              return <Article key={a.id} {...a} />;
            })
          )}
        </div>
      </div>
    );
  }
}
0 голосов
/ 23 мая 2018

Я думаю, что вы подключены только к магазину, но никогда не вызывали функцию startSetArticles().Попробуйте добавить (это будет работать с вашим текущим mapDispatchToProps)

  componentDidMount() {
    this.props.articles()
  }

Это должно вызвать функцию, которая должна обновить ваш магазин.

И я бы порекомендовал вместо:

const mapDispatchToProps = dispatch => ({
  articles: () => dispatch(startSetArticles())
});

Вы должны просто сделать это:

const mapDispatchToProps = dispatch => ({
  startSetArticles: () => dispatch(startSetArticles())
});

Тогда вам придется сделать это, что имеет больше смысла.

  componentDidMount() {
    this.props.startSetArticles()
  }

Я думаю, что ваша путаница связана с тем, как использоватьmapDispatchToProps.Когда вы mapDispatchToProps, он DOES NOT сразу вызывает эту функцию.Вам все равно нужно будет вызвать эту функцию где-то в компоненте.В вашем случае componenetDidMount имеет смысл.

И затем вам нужно добавить mapStateToProps, который подключится к хранилищу и фактически вернет данные.

Вот рабочий пример:

export class Morphology extends React.Component {
  componentDidMount() {
    document.title = 'Eflows | Morphology';
    this.props.fetchGeoSites();
  }

  render() {
    return (
      <div>
        <div style={styles.banner} />
        <Layout geoSites={this.props.geoSites} />
      </div>
    );
  }
}

Morphology.propTypes = {
  fetchGeoSites: PropTypes.func,
  geoSites: PropTypes.array,
};

const mapStateToProps = state => {
  return {
    geoSites: state.geoSite.geoSites,
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetchGeoSites: () => dispatch(fetchGeoSites()),
  };
};

Я использую тот же метод, вы можете посмотреть в этом больше с этим репо: https://github.com/leogoesger/eflow-client

0 голосов
/ 23 мая 2018

Вы должны использовать первый параметр connect, чтобы получить состояние articles.

connect(state => ({ articles: state.articles }), ...)

Чтобы установить состояние articles, вам нужно вызвать startSetArticles где-нибудь как componentDidMountили в файле, где вы объявляете ваш store (если вы хотите, чтобы он вызывался при загрузке приложения) с помощью store.dispatch(startSetArticles()).

...