我创建了一个名为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
}
}
答案 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
希望这有帮助!