反应组件不反映商店的当前状态

时间:2019-05-19 14:10:38

标签: reactjs redux

我已经实现了显示课程的组件。在同一组件内,具有用于当用户搜索特定课程时过滤课程的功能。

我遇到的问题是,当我调度一个用于过滤课程的操作时,redux存储显示课程状态已更新为仅包含与搜索查询匹配的课程,但组件未反映新状态(即仍显示所有课程)。我该如何解决这个问题?

这是我到目前为止已经实现的

动作

export const retrieveAllCourses = (url, query) => dispatch => {
  return axios
    .get(url + `?title=${query}`, {
      headers: myHeaders
    })

    .then(res => {
      const fetchall = {
        type: ACTION_TYPE.VIEW_COURSES,
        payload: res.data.courses
      };
      dispatch(fetchall);
    })
    .catch(error => {
      toast.error(error, { autoClose: 3500, hideProgressBar: true });
    });
};

减速器

import ACTION_TYPE from "../../actions/actionTypes";

const initialState = {
  courses: [],
};

const coursesReducer = (state = initialState, action) => {
  switch (action.type) {

  case ACTION_TYPE.VIEW_COURSES:
    return {
      ...state,
      courses: state.courses.concat(action.payload.results),
    };

  default:
    return state;
  }
};

export default coursesReducer;

搜索组件

import React from "react";
import PropTypes from "prop-types";

class Search extends React.Component {
  state = {
    search: ""
  };

  handleChange = ev => {
    ev.preventDefault();
    const { onChange } = this.props;
    const search = ev.target.value;
    this.setState({ search });
    if (onChange) {
      onChange(search);
    }
  };

  handleSearch = ev => {
    ev.preventDefault();
    const { onSearch } = this.props;
    const { search } = this.state;
    if (onSearch) {
      onSearch(search);
    }
  };

  render() {
    const { id } = this.props;

    window.onload = function() {
      var input = document.getElementById("search-input");
      input.addEventListener("keyup", function(event) {
        if (event.keyCode === 13) {
          event.preventDefault();
          document.getElementById("mySearchBtn").click();
        }
      });

    };

    return (
      <React.Fragment>
        <form id={id}>
          <div className="search-container">
            <div className="input-group">
              <input
                type="text"
                id="search-input"
                className="search-input form-control"
                placeholder="Search lessons"
                onChange={this.handleChange}
              />
            </div>
            <div>
              <button id="mySearchBtn" onClick={this.handleSearch} />
            </div>
          </div>
        </form>
      </React.Fragment>
    );
  }
}

Search.propTypes = {
  onChange: PropTypes.func,
  onSearch: PropTypes.func,
  id: PropTypes.number
};

export default Search;

导航栏组件

import React from "react";
import PropTypes from "prop-types";
import Search from "../../components/courses/Search";

export const LoggedInNavBar = ({ handleSearch, handleSearchChange}) => {
  return (
    <div className="row bobo-menu">
      <div className="col-sm">
        <div className="logo-container">
          <a href={"/courses"}>
            <h1 id="logo" className="hidden">
              TUTORIALS
            </h1>
          </a>
        </div>
      </div>

      <div className="col-sm">
        <Search onSearch={handleSearch} onChange={handleSearchChange} />
      </div>

      <div className="col-sm">
        <p id="motto">
          TUTORIALS<span className="text-succes"> AND</span> LEARNING{" "}
          <span className="text-succes">FOR ALL</span>
        </p>
      </div>

      <div className="col-sm">
        <div className="row row__menu__icons">
          <div className="col-lg-3 col-md-3 col-sm-3">
            <a
              id="title"
              href="/create"
              className="btn btn-login "
              data-mode="signin"
            >
              {" "}
              <i className="fas fa-plus" />
            </a>
          </div>
          <div className="col-lg-3 col-md-3 col-sm-3">
            <a
              id="title"
              href="/create"
              className="btn btn-login "
              data-mode="signin"
            >
              <i className="far fa-user" />
            </a>
          </div>
          <div className="col-lg-3 col-md-3 col-sm-3">
            <a
              id="title"
              href="/me/stories"
              className="btn btn-login "
              data-mode="signin"
            >
              <i className="fas fa-book" />
            </a>
          </div>
          <div className="col-lg-3 col-md-3 col-sm-3">
            <a
              id="title"
              href="/create"
              className="btn btn-login "
              data-mode="signin"
            >
              <i className="fas fa-sign-out-alt" />
            </a>
          </div>
        </div>
      </div>
      <br />
      <br />
    </div>
  );
};

LoggedInNavBar.propTypes = {
  handleSearch: PropTypes.func,
  handleSearchChange: PropTypes.func
};

课程组件

import React, { Fragment } from "react";
import { details } from "../../routes/protectedRoutes";
import { AUTHENTICATED } from "../../utils/myHeaders";
import { ViewAllCourses } from "../../views/courses/viewSearchResults";
import { retrieveAllCourses } from "../../actions/courseActions/courseAction";
import { LoggedInNavBar } from "../navigation/LoggedIn";
import { API_URLS } from "../../appUrls";
import PropTypes from "prop-types";
import { connect } from "react-redux";

export class Courses extends React.Component {
  constructor(props) {
    super(props);
    this.user = details(AUTHENTICATED);
    this.state = {
      search: ""
    };
  }

  componentDidMount() {
    this.fetchCourses();
  }

  fetchCourses = (searchStr = null) => {
    let Url = API_URLS.FETCH_CREATE_ARTICLES;
    const { search } = this.state;
    const query = searchStr !== null ? searchStr : search;
    this.props.dispatch(retrieveAllCourses( Url, query ));
  };

  handleSearch = search => {
    this.setState({ search });
    this.fetchCourses(search);
  };

  handleSearchChange = search => {

    if (!search) {
      this.setState({ search });
      this.fetchCourses(search);
    }
  };

  render() {
    const { allCourses } = this.props;


    return (
        <div>

        <LoggedInNavBar
          handleSearchChange={this.handleSearchChange}
          handleSearch={this.handleSearch}
        />

        <ViewAllCourses results={allVideos} />
        </div>

    );

  }
}

Courses.propTypes = {
  dispatch: PropTypes.func.isRequired,
  allCourses: PropTypes.array
};

const mapStateToProps = state => ({
  allCourses: state.coursesReducer.courses
});
const mapDispatchToProps = dispatch => ({ dispatch });

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

API响应enter image description here

1 个答案:

答案 0 :(得分:1)

  1. 在您的化简器中,为什么要将它与以前的状态结果并置?如果这样做,您的过滤将永远不会显示关联的数据。

  2. 我在您的动作分配中看不到payload.results。不是action.payload而不是action.payload.results吗?

return {
  ...state,
  courses: action.payload,
}

Reducer中没有状态变量videos。您正在分派和存储courses,所以您必须听:

const mapStateToProps = state => ({
  allCourses: state.coursesReducer.courses
});

希望这会有所帮助!