React Redux - 如何存储表单状态,以便在用户返回页面时可以再次填充它

IT技术 reactjs redux react-redux
2021-05-26 08:16:53

我有一个加载结果的搜索表单。除了在表单字段中选择的值之外,所有内容都在 Redux 状态下更新。

假设下面的搜索显示了 3 个结果。用户点击结果 #2 并且不喜欢它。单击后退按钮但表单状态被清除。我怎样才能避免这种情况并确保表单状态保持不变?

我将结果存储在 Redux 中并能够加载它但不确定如何处理状态。如果可能的话,我不想使用诸如 redux-form 之类的包,因为这是我唯一需要存储表单状态的地方。

在此处输入图片说明

当我更改选择时,状态不会更新。对于专家来说,这可能是代码的细微变化,但我是初学者,这是我的第一个 React-Redux 应用程序。

此外,当我离开页面时,不会保留上次存储的状态。这可能是因为formValues: {}我正在初始化的本地状态,但没有这个,就会出现错误。我试图删除本地状态并只使用props,但它在这一行的选择框中给了我错误 -value={this.state.formValues['gender']}

下面是该组件的整体代码:

import React, { Component } from 'react'
import { get } from 'axios'
import { connect } from 'react-redux'
import { FadeIn } from 'animate-components'
import {
  getSearchResults,
  setSearchedOnce,
  setPageNum,
  setFormValues,
} from '../../actions/searchresults'
import SearchResult from './Result/searchResult'
import SearchNoResult from './Result/searchNoResult'

class SearchAdvanced extends Component {
  constructor(props) {
    super(props)
    this.state = { searchedOnce: false, users: [] }
  }

  handleChange(event) {
    event.preventDefault()
    this.props.setFormValues(this.props.formValues)
  }

  handleSubmit(event) {
    event.preventDefault()
    this.props.setSearchedOnce(true)
    const apiSearchURL = `/api/search/religion/${this.props.formValues.religion}/gender/${this.props.formValues.gender}`
    get(apiSearchURL, { maxContentLength: 400 })
    .then((searchResults) => {
      this.props.getSearchResults(searchResults)
    })
  }

  loadMoreClick() {
    this.props.setPageNum(this.props.pageNo + 1)
  }

  render() {
    const { users } = this.props
    let mapPageNo = this.props.pageNo
    let map_usersList = users.data && users.data.slice(0, mapPageNo * 2).map((userlist => (
      <SearchResult key={userlist.id} {...userlist} />
    )))
    let mapSearchedOnce = this.props.searchedOnce
    return (
      <div>
      <FadeIn duration="300ms">
        <div className="mid_rig_inner">
          <div className="mid_inner">
            <ul>
            { mapSearchedOnce
              ?  map_usersList
              :  <SearchNoResult/>
            }
            {
              mapSearchedOnce ?
              (mapPageNo * 2 >= 3)
              ?
              <div className="text-center my3 text-danger">
                No more profiles. Try to modify search criteria.
              </div> :
              <div className="text-center my3">
              <button type="button" className="btn btn-primary" onClick={this.loadMoreClick.bind(this)}>
                   Load More
                </button>
              </div>
              : ''
            }
            </ul>
          </div>
          <div className="rig_inner">
          <div className="my-4">
            <div className="recomm">
              <div className="recomm_top">
                <span>Search</span>
              </div>
            </div>
            <div className="search_advan_box">
              <form onSubmit={this.handleSubmit.bind(this)}>
                <select
                  name="religion"
                  className="mb-2"
                  value={this.props.formValues.religion}
                  onChange={this.handleChange.bind(this)}
                >
                  <option value="" disabled="">
                    Select Religion
                  </option>
                  <option value="Any">Any Religion</option>
                  <option>Christian</option>
                  <option>Hindu</option>
                  <option>Muslim</option>
                  <option>Jain</option>
                  <option>Buddhist</option>
                  <option>Sikh</option>
                  <option>Parsi</option>
                  <option>Jewish</option>
                  <option>Spiritual</option>
                  <option>No Religion</option>
                  <option>Other</option>
                </select>

                <select
                  name="gender"
                  className="mb-2"
                  value={this.props.formValues.gender}
                  onChange={this.handleChange.bind(this)}
                >
                  <option value="" disabled="">
                    Select Gender
                  </option>
                  <option>Male</option>
                  <option>Female</option>
                  <option>Other</option>
                </select>
                <input
                  type="submit"
                  className="my-4 btn btn-primary p2"
                  value={mapSearchedOnce ? "Refine Results":"Search Profiles"}
                />
              </form>
            </div>
          </div>

          </div>
        </div>
        </FadeIn>
      </div>
    )
  }
}

const mapStateToProps = state => ({
  users: state.Result.users,
  searchedOnce: state.Result.searchedOnce,
  pageNo: state.Result.pageNo,
  formValues: state.Result.formValues
})
const mapDispatchToProps = {
    getSearchResults,
    setSearchedOnce,
    setPageNum,
    setFormValues
}

export default connect(mapStateToProps, mapDispatchToProps)(SearchAdvanced)
1个回答

当我更改选择时状态不会更新

这是因为您没有在您的handleChange方法中分派 Redux 操作,而是在您的方法中分派handleSubmit只需在 in 中调度适当的操作即可handleChange解决此问题。

当我离开页面时,不会保留上次存储的状态

这是因为之前(在你离开之前)的值只会保存在 Redux 存储中,而表单字段是从SearchAdvanced组件的本地状态填充的

要很好地解决这个问题,您应该完全摆脱您的本地状态。而是仅使用 Redux 存储。保持两者完整是不必要的,并且破坏了 Redux 的“单一事实来源”。我建议你取消本地状态,只更新 Redux 状态,然后将值从 Redux 存储(props对于组件)传递给表单输入

关于您尝试过此操作但出现错误的说明:您需要更改以下内容:

<input value={ this.state.formValues.someValue }/>

<input value={ this.props.formValues.someValue }/>

其中,formValues来自于终极版店。

更新

现在的问题是线路

this.props.setFormValues(this.props.formValues)

handleChange. 您正在使用旧的 formValues 进行更新,因此商店实际上从未更新过。我想你想要这样的东西:

handleChange(event) {
    event.preventDefault();
    const { name, value, type, checked } = event.target;
    this.props.setFormValues({
        ...this.props.formValues,
        [name]: type === 'checkbox' ? checked : value
    });
}

这样您就可以formValues使用用户的输入更新商店三元运算符对于复选框输入是必需的,因为value选中的复选框的'on'不是true,但checked属性是true如果选中的。

额外的

似乎您将 dispatch 方法SearchAdvanced从父级传递给了via props。您可以(并且应该)通过使用 的第二个参数(connectmapDispatchToProps. 下面是一个例子:

const mapDispatchToProps = {
    getSearchResults,
    setSearchedOnce,
    setPageNum,
    setFormValues
}

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

然后,您可以将其中任何一个作为已经绑定了调度的方法调用。所以

this.props.dispatch(setSearchedOnce(true))

变成

this.props.setSearchedOnce(true)

并且您可以从父组件中删除调度的传递。

文档connecthttps : //github.com/reduxjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options