我无法从 reducer 获取数据到组件

I can't fetch the data from reducer to component

我正在尝试将数据从 reducer 传递到组件并作为 props 接收。

但是数据 return 未定义,所以我尝试控制 reducer 和 action 上的数据,但没问题。来自 API 的数据没有任何问题,但它总是 return 组件未定义。我的错在哪里?

动作

export default ProfileTab;

import axios from 'axios';
import { BASE, API_KEY } from '../config/env';
export const FETCHED_MOVIES = 'FETCHED_MOVIES';

export function fetchMovies() {
  return (dispatch) => {
    axios
      .get(`${BASE}s=pokemon&apikey=${API_KEY}`)
      .then((result) => result.data)
      .then((data) =>
        dispatch({
          type: FETCHED_MOVIES,
          payload: data.Search,
        }),
      );
  };
}

减速器

import { FETCHED_MOVIES } from '../actions/movies';

const initialState = {
  fetching: false,
  fetched: false,
  movies: [],
  error: {},
};

export default (state = initialState, action) => {
  switch (action.type) {
    case 'FETCHED_MOVIES':
      return {
        ...state,
        movies: action.payload,
      };
    default:
      return state;
  }
};

组件

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import { fetchMovies } from '../../actions/movies';

class Case extends Component {
  static propTypes = {
    movies: PropTypes.object.isRequired,
  };

  constructor(props) {
    super(props);
  }

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

  onChangeHandler = (e) => {
    this.setState({
      input: e.target.value,
    });
  };

  render() {
    console.log(this.props.movies);

    return (
      <div>
        <div className="movies-root">
          <div className="movies-wrapper">
            <div className="movies-container safe-area">
              <h1>mert</h1>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

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

const mapDispatchToProps = {
  fetchMovies,
};

export default connect(mapStateToProps, mapDispatchToProps)(Case);

那是因为您的 mapDispatchToProps 函数应该 return 一个对象并以 dispatch 作为参数。 returned 对象中的每个字段都应包含一个调度您的操作的函数。

所以尝试这样的事情:

const mapDispatchToProps = dispatch => {
  return {
    fetchMovies: () => dispatch(fetchMovies())
  }
}

在连接语句中这样做:

export default connect(mapStateToProps,{fetchMovies})(Case);

并从您的代码中删除 mapDispatchToProps 函数。

将 props 作为一个对象来分发是非常不正确的。试试这个,它应该可以工作。

尽管已经有 ,但我不确定它的正确性如何,因为按照您对最新 react (16.13. 1) 和 react-redux (7.2.1) 版本(我不确定早期版本)。

现在,假设您的问题包含整个代码,则缺少两件重要的事情:

  1. 正在创建商店:

    import { createStore } from "redux";
    const store = createStore(reducer);
    

    并将其传递给 Provider 组件:

    <Provider store={store}>
    
  2. 如果继续按上述操作,您会看到 this.props.fetchMovies 发出以下错误:

    Actions must be plain objects. Use custom middleware for async actions.

    要修复它,按照它说的去做并添加一个中间件,例如thunk:

    import { createStore, applyMiddleware } from "redux";
    import thunk from "redux-thunk";
    const store = createStore(rootReducer, applyMiddleware(thunk));
    

下面是完整代码。请注意,我将 fetchMovies“拆分”为两个函数:sync 和 async,以说明两者之间的区别用法。为了这个答案的可读性,我还修改了您的代码(主要是更短)。您也可以 see a live demo here:

文件app.js

import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchMoviesSync, fetchMoviesAsyncMock } from "./api";

class App extends Component {
  componentDidMount() {
    this.props.fetchMoviesSync();
    this.props.fetchMoviesAsyncMock();
  }
  render() {
    return (
      <div>
        <div className="movies-root">
          <div className="movies-wrapper">
            <div className="movies-container safe-area">
              {this.props.movies.join("\n")}
            </div>
          </div>
        </div>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({ movies: state.movies });
const mapDispatchToProps = {
  fetchMoviesSync,
  fetchMoviesAsyncMock
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

文件api.js

export const FETCHED_MOVIES = "FETCHED_MOVIES";

export const fetchMoviesSync = () => ({
  type: FETCHED_MOVIES,
  payload: ["movie1", "movie2", "movie3", "movie4"]
});
export const fetchMoviesAsyncMock = () => (dispatch) => {
  dispatch({
    type: FETCHED_MOVIES,
    payload: ["movie5", "movie6", "movie7", "movie8"]
  });
};

文件reducer.js

const initialState = {
  movies: [],
};

export default (state = initialState, action) => {
  switch (action.type) {
    case "FETCHED_MOVIES":
      return {
        ...state,
        movies: state.movies.concat(action.payload)
      };
    default:
      return state;
  }
};

文件index.js

import React from "react";
import ReactDOM from "react-dom";
import Case from "./app";
import reducer from "./reducer";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import thunk from "redux-thunk";

let store = createStore(reducer, applyMiddleware(thunk));
ReactDOM.render(
  <Provider store={store}>
    <Case />
  </Provider>,
  document.getElementById("container")
);

文件index.html

<body>
  <div id="container"></div>
</body>