React Redux - 如何存储表单状态,以便在用户返回页面时可以再次填充它 [英] React Redux - How to store form state so that it can be populated again when user returns to page

查看:47
本文介绍了React Redux - 如何存储表单状态,以便在用户返回页面时可以再次填充它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

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

这里是组件的整体代码:

import React, { Component } from 'react'从'axios'导入{获取}从'react-redux'导入{连接}从动画组件"导入 { FadeIn }进口 {获取搜索结果,setSearchedOnce,设置页数,设置表单值,} 来自'../../actions/searchresults'从 './Result/searchResult' 导入 SearchResult从 './Result/searchNoResult' 导入 SearchNoResult类 SearchAdvanced 扩展组件 {构造函数(道具){超级(道具)this.state = { searchedOnce: false, users: [] }}句柄变化(事件){event.preventDefault()this.props.setFormValues(this.props.formValues)}处理提交(事件){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)})}加载更多点击(){this.props.setPageNum(this.props.pageNo + 1)}使成为() {const { 用户 } = this.props让 mapPageNo = this.props.pageNo让 map_usersList = users.data &&users.data.slice(0, mapPageNo * 2).map((userlist => (<SearchResult key={userlist.id} {...userlist}/>)))让 mapSearchedOnce = this.props.searchedOnce返回 (<div><淡入持续时间="300ms"><div className="mid_rig_inner"><div className="mid_inner"><ul>{ mapSearchedOnce?地图用户列表:<SearchNoResult/>}{mapSearchedOnce ?(mapPageNo * 2 >= 3)?<div className="text-center my3 text-danger">没有更多的个人资料.尝试修改搜索条件.

:<div className="text-center my3"><button type="button" className="btn btn-primary" onClick={this.loadMoreClick.bind(this)}>装载更多

:''}

<div className="rig_inner"><div className="my-4"><div className="推荐"><div className="recomm_top"><span>搜索</span>

<div className="search_advan_box"><form onSubmit={this.handleSubmit.bind(this)}><选择名称=宗教"类名=mb-2"值={this.props.formValues.religion}onChange={this.handleChange.bind(this)}><option value="" disabled="">选择宗教</选项><option value="Any">Any Religion</option><option>Christian</option><option>印度教</option><option>穆斯林</option><option>Jain</option><option>佛教</option><option>锡克教</option><option>Parsi</option><option>犹太</option><option>精神</option><option>无宗教</option><option>其他</option></选择><选择姓名=性别"类名=mb-2"值={this.props.formValues.gender}onChange={this.handleChange.bind(this)}><option value="" disabled="">选择性别</选项><option>男</option><option>女</option><option>其他</option></选择><输入类型=提交"className="my-4 btn btn-primary p2"值={mapSearchedOnce ?"优化结果":"搜索配置文件"}/></表单>

</淡入>

)}}const mapStateToProps = state =>({用户:state.Result.users,searchedOnce:state.Result.searchedOnce,pageNo: state.Result.pageNo,formValues: state.Result.formValues})const mapDispatchToProps = {获取搜索结果,setSearchedOnce,设置页数,设置表单值}导出默认连接(mapStateToProps,mapDispatchToProps)(SearchAdvanced)

解决方案

更改选择时状态不会更新

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

<块引用>

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

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

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

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

其中 formValues 来自 Redux 存储.

更新

问题是线路

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

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

handleChange(event) {event.preventDefault();const { 名称、值、类型、检查} = event.target;this.props.setFormValues({...this.props.formValues,[名称]:输入 === '复选框' ?检查:值});}

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

额外

您似乎通过父级的 props 将 dispatch 方法传递给 SearchAdvanced.您可以(并且应该)通过使用 connect 的第二个参数 mapDispatchToProps 来更干净地完成此操作.举个例子:

const mapDispatchToProps = {获取搜索结果,setSearchedOnce,设置页数,设置表单值}导出默认连接(mapStateToProps,mapDispatchToProps)(SearchAdvanced);

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

this.props.dispatch(setSearchedOnce(true))

变成

this.props.setSearchedOnce(true)

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

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

I have a search form that loads results. Everything gets updated in the Redux state except for the values selected in the form fields.

Lets say the search below shows 3 results. User clicks on result #2 and does not like it. The click the back button but the form state is cleared. How can I avoid this and make sure the form state stays ?

I am storing the results in Redux and able to load that but not sure how to handle state. I dont want to use packages such as redux-form if possible because this is the only place I need to store form state.

The state does not update when I change the selections. This is probably a slight change in code for an expert but I am beginner and this is my first React-Redux app.

Also, when I navigate away from the page, the state that was last stored is not retained. This is probably because of the local state formValues: {} that I am initializing but without this, there are errors. I tried to delete local state and just use props but it is giving me errors on the select box at this line - value={this.state.formValues['gender']}

Here is the overall code of the component:

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)

解决方案

The state does not update when I change the selections

This is because you are not dispatching a Redux action in your handleChange method, only in your handleSubmit method. Simply dispatching the appropriate action in handleChange will resolve this issue.

when I navigate away from the page, the state that was last stored is not retained

This is because the values from before (before you navigate away) will only be kept in the Redux store, while the form fields are populated from the local state of the SearchAdvanced component.

To solve this one well, you should get rid of your local state entirely. Instead only use the Redux store. Keeping both intact is unnecessary and breaks the 'Single Source of Truth' that Redux is meant for. I recommend you do away with the local state and only update the Redux state and then pass values to the form inputs from the Redux store (props for the component).

Regarding your note that you tried this, but get errors: you need to change anything like:

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

to

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

where formValues comes from the Redux store.

Update

Problem now is the line

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

in handleChange. You're using the old formValues to update, so the store never actually updates. I think you want something like:

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

So that you are updating the store's formValues with the input from the user. The ternary operator is necessary for checkbox inputs since the value of a checked checkbox is 'on' rather than true, but the checked attribute is true if checked.

Extra

It seems that you pass the dispatch method to the SearchAdvanced via props from the parent. You can (and should) do this more cleanly by using the second argument of connect, which is mapDispatchToProps. Here's an example:

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

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

Then you can just call any of these as methods that already have a dispatch bound to them. So

this.props.dispatch(setSearchedOnce(true))

becomes

this.props.setSearchedOnce(true)

and you can remove the passing of the dispatch from the parent component.

Docs on connect: https://github.com/reduxjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options

这篇关于React Redux - 如何存储表单状态,以便在用户返回页面时可以再次填充它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆