无法使用redux

时间:2017-12-04 00:12:45

标签: reactjs redux react-redux redux-form

我创建了一个名为siteEdit.js的容器。它处理创建&编辑"网站"。

我设置了actionCreators来处理表单数据并将其提交给API。这非常有效。

但是当你使用包含ID的路径访问容器时,它将运行一个actionCreator来获取" Site"基于id参数的数据。

这一切都按预期工作,但由于我使用redux,我使用props设置Input值。例如,this.props.title

我现在试图远离使用redux-form包。

集装箱:

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

import {createSite, getSite} from '../../actions/siteActions';

class SiteEdit extends Component {
  constructor(props) {
    super(props)
    this.state = {
      title: '',
      url: '',
      description: '',
      approvedUsers: []
    }
    this.handleSubmit = this.handleSubmit.bind(this)
    this.handleInputChange = this.handleInputChange.bind(this)
  }

  componentWillMount() {
    if(this.props.params.id) {
      this.props.dispatch(getSite(this.props.params.id))
    }
  }



  handleInputChange(e) {
    const target = e.target
    const value = target.type === 'checkbox' ? target.checked : target.value
    const name = target.name

    this.setState({
      [name]: value
    })
  }

  handleSubmit(e) {
    e.preventDefault()
    this.props.dispatch(createSite(this.state))
  }

  render() {

    const {title, url, description, approvedUsers} = this.props

    return (
      <div className="SiteEdit">
        <h1>NEW SITE</h1>
        <form onSubmit={this.handleSubmit}>

          <div className="block">
            <label>Site Name</label>
            <input 
              className="input" 
              type="text"
              value={title ? title : this.state.title}
              onChange={this.handleInputChange} 
              name="title" />
          </div>
          <div className="block">
            <label>Site URL</label>
            <input 
              className="input" 
              type="text"
              value={this.state.url} 
              onChange={this.handleInputChange}
              name="url" />
          </div>
          <div className="block">
            <label>Description</label>
            <input
              className="textarea"
              type="textarea"
              value={this.state.description}
              onChange={this.handleInputChange}
              name="description" />
          </div>
          <div className="block">
            <label>Approved Users</label>
            <input
              className="input"
              type="text"
              value={this.state.approvedUsers}
              onChange={this.handleInputChange}
              name="approvedUsers" />
          </div>

          <button className="button--action">Create</button>
        </form>
      </div>
    )
  }
}

const mapStateToProps = (state) => ({
  title: state.sites.showSite.title,
  url: state.sites.showSite.url,
  description: state.sites.showSite.description,
  approvedUsers: state.sites.showSite.approvedUsers
})

SiteEdit = connect(mapStateToProps)(SiteEdit)

export default SiteEdit

ActionCreators:

import config from '../config'
import { push } from 'react-router-redux'


const apiUrl = config.api.url

// List all sites
export const LIST_SITES_START = 'LIST_SITES_START'
export const LIST_SITES_SUCCESS = 'LIST_SITES_SUCCES'
export const LIST_SITES_ERROR = 'LIST_SITES_ERROR'

export function sitesListStart(data) {
  return { type: LIST_SITES_START, data }
}

export function sitesListSuccess(data) {
  return { type: LIST_SITES_SUCCESS, data }
}

export function sitesListError(data) {
  return { type: LIST_SITES_ERROR, data }
}

export function listSites() {
  return (dispatch) => {
    dispatch(sitesListStart())
    fetch(`${apiUrl}/listSites`)
    .then(res => res.json())
    .then(json => {
      dispatch(sitesListSuccess(json))
    })
    .catch(error => {
      dispatch(sitesListError)
    })
  }
}

// Create & Edit Sites
export const CREATE_SITE_START = 'CREATE_SITE_START'
export const CREATE_SITE_SUCESS = 'CREATE_SITE_SUCCESS'
export const CREATE_SITE_ERROR = 'CREATE_SITE_ERROR'

export function siteCreateStart(data) {
  return { type: CREATE_SITE_START, data}
}

export function siteCreateSuccess(data) {
  return { type: CREATE_SITE_SUCCESS, data}
}

export function siteCreateError(error) {
  return { type: CREATE_SITE_ERROR, error}
}

export function createSite(data) {
  return (dispatch) => {
    dispatch(siteCreateStart())
    fetch(`${apiUrl}/createSite`, {
      method: 'post',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    })
    .then(res => res.json())
    .then(json => {
      dispatch(push('/'))
      dispatch(siteCreateSuccess())
    })
    .catch(error => {
      dispatch(siteCreateError())
    })

  }
}

// Get Single Site
export const GET_SITE_START = 'GET_SITE_START'
export const GET_SITE_SUCCESS = 'GET_SITE_SUCCESS'
export const GET_SITE_ERROR = 'GET_SITE_ERROR'

export function getSiteStart(data) {
  return { type: GET_SITE_START, data}
}

export function getSiteSuccess(data) {
  return { type: GET_SITE_SUCCESS, data}
}

export function getSiteError(error) {
  return { type: GET_SITE_ERROR, error}
}

export function getSite(id) {
  return (dispatch) => {
    dispatch(getSiteStart())
    fetch(`${apiUrl}/getSite/${id}`)
    .then(res => res.json())
    .then(json => {
      dispatch(getSiteSuccess(json))
    })
    .catch(error => {
      dispatch(getSiteError())
    })
  }
}

减速:

import {push} from 'react-router-redux'
import {
  LIST_SITES_START,
  LIST_SITES_SUCCESS,
  LIST_SITES_ERROR,
  GET_SITE_START,
  GET_SITE_SUCCESS,
  GET_SITE_ERROR
} from '../actions/siteActions'

const initialState = {
  sitesList: {
    sites: [],
    error: null,
    loading: true
  },
  showSite: {
    title: '',
    url: '',
    description: '',
    approvedUsers: [],
    loading: true
  }
}

export default function (state = initialState, action) {
  switch (action.type) {
    // List Sites
    case LIST_SITES_START:
      return Object.assign({}, state, {
        sitesList: Object.assign({}, state.sitesList, {
          loading: true
        })
      })
    case LIST_SITES_SUCCESS:
      return Object.assign({}, state, {
        sitesList: Object.assign({}, state.sitesList, {
          sites: action.data,
          loading: false
        })
      })
    case LIST_SITES_ERROR:
      return Object.assign({}, state, {
        error: action.error,
        loading: false
      })

    case GET_SITE_START:
      return Object.assign({}, state, {
        showSite: Object.assign({}, state.showSite, {
          loading: true
        })
      })
    case GET_SITE_SUCCESS:
      return Object.assign({}, state, {
        showSite: Object.assign({}, state.showSite, {
          ...action.data,
          loading: false
        })
      })
    case GET_SITE_ERROR:
      return Object.assign({}, state, {
        showSite: Object.assign({}, state.showSite, {
          error: action.error,
          loading: false
        })
      })

    default:
      return state
  }
}

1 个答案:

答案 0 :(得分:1)

您正在为props.title取得先例的值设置三元组,就像重新迭代一样 -

 const { title } = this.props;
 ...
 value={title ? title : this.state.title}

您的onChange逻辑是正确的,并且可能正确地更新了您的组件本地状态,但是您仍然拥有this.props.title,因此它将在该三元组中占据先例。

有很多方法可以解决这个问题,它实际上取决于操作的顺序(也就是说,当props.title不真实时)。假设您在组件安装时拥有标题,您可以在构造函数中执行以下操作:

 constructor(props) {
    super(props)
    this.state = {
      title: props.title,   << set default here
      url: '',
      description: '',
      approvedUsers: []
    }

然后在输入中你只需要将值设置为状态标题

value={this.state.title}

这取决于props.title值何时进入您的组件,如果它不适用于mount,这将无法按预期工作。

你也可以传递一个函数来评估输入值的所有这些 - 你可以在其中更详细地检查props.title和state.title,并决定返回哪一个作为你的值。

 <input value={this.returnTitleValue} ..  << something like so

希望这有帮助!