Реагировать Redux не обновляя ввод текста на изменение - PullRequest
0 голосов
/ 30 сентября 2019

Я видел похожие вопросы, но они, похоже, не помогают. У меня есть проект React, в котором я использую Redux.

Мой index.js выглядит следующим образом:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";

import reducer from "./store/reducer";

import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";

const store = createStore(reducer);

const app = (
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>
);

ReactDOM.render(app, document.getElementById("root"));

serviceWorker.unregister();

Мой reducer.js выглядит так:

import * as actionTypes from "./actions";

const initialState = {
  searchValue: "",
  finalSearchValue: ""
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case actionTypes.UPDATE_INPUT_VALUE:
      return {
        searchValue: state.searchValue
      };
    case actionTypes.SUBMIT_QUERY:
      return {
        finalSearchValue: state.finalSearchValue
      };
    default:
      return state;
  }
};

export default reducer;

И мой Songfinder.js - где я пытаюсь mapStateToProps и mapDispatchToProps, выглядит так:

import React, { Component } from "react";
import { connect } from "react-redux";
import PanelSearchResults from "../../components/PanelSearchResults/PanelSearchResults";
import Playlist from "../Playlist/Playlist";

import classes from "./SongFinder.css";
import Auxilliary from "../../hoc/Auxilliary";
import * as actionTypes from "../../store/actions";

class SongFinder extends Component {
  props: {
    searchValue: string;
    finalSearchValue: string;
  };

  componentDidMount() {
    console.log(this.props);
  }

  updateInputValue(evt) {
    this.props.onUpdateSearchValue(evt.target.value);
  }

  onSubmitQueryHandler() {}

  render() {
    if (this.props) {
      return (
        <Auxilliary>
          <div className={classes.panel}>
            <input
              className="searchBox"
              type="text"
              value={this.props.searchValue}
              onChange={evt => this.updateInputValue(evt)}
            />
            <button type="submit" onClick={this.onSubmitQueryHandler}>
              Submit
            </button>
          </div>
          <div className={classes.panel}>
            <h1>Playlist</h1>
            <Playlist />
          </div>
          <PanelSearchResults search={this.props.finalSearchValue} />
        </Auxilliary>
      );
    } else {
      return null;
    }
  }
}

const mapStateToProps = state => {
  return {
    searchValue: state.searchValue,
    finalSearchValue: state.finalSearchValue
  };
};

const mapDispatchToProps = dispatch => {
  return {
    onUpdateSearchValue: value =>
      dispatch({
        type: actionTypes.UPDATE_INPUT_VALUE,
        searchValue: value
      }),
    onSubmitQuery: value =>
      dispatch({
        type: actionTypes.SUBMIT_QUERY,
        finalSearchValue: value
      })
  };
};

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

Каждый раз, когда изменяется текст ввода, я хочу, чтобы состояние обновлялось с помощью mapDispatchToProps, и я хочусобытие onChange для запуска обработчика updateInputValue, который должен вызывать onUpdateSearchValue в mapDispatchToProps, отправляя ему evt.target.value.

Вырывая мои волосы, пытаясь выяснить, почему это не работает. Я в Реакте 16.6.3 - это ошибка Typescript? Оба значения в моем initialState, объявленном в редукторе, регистрируются на консоли через componentDidMount () в Songfinder.js, поэтому для этого компонента доступны реквизиты?

1 Ответ

1 голос
/ 01 октября 2019

Похоже, ваша проблема в том, что редуктор фактически не создает никакого нового состояния, потому что вы ссылаетесь на state вместо action при получении нового состояния. Параметр state содержит предыдущее состояние с момента последнего запуска редуктора, а action содержит информацию, необходимую для получения нового состояния на этот раз. Вот так:

import * as actionTypes from "./actions";

const initialState = {
  searchValue: "",
  finalSearchValue: ""
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case actionTypes.UPDATE_INPUT_VALUE:
      return {
        searchValue: action.searchValue,
        finalSearchValue: ""
      };
    case actionTypes.SUBMIT_QUERY:
      return {
        searchValue: "",
        finalSearchValue: action.finalSearchValue
      };
    default:
      return state;
  }
};

export default reducer;

Я также добавил дополнительные поля в приведенные выше результаты, потому что редуктор, вероятно, должен возвращать полное состояние каждый раз (в той же форме, что и initialState).

...