在redux中使用一个函数更新对象状态的最佳方法是什么?
我有3个输入--如果可能的话,我想用一个函数更新对应的输入字段到redux对象字段......或者最佳实践。
/ Contact.js
this.state = {
contactInfo: {
firstName: '',
address: '',
city: '',
}
}
onChangeInfo = (event, action) => {
const { dispatch } = this.props;
const { contactInfo } = this.state;
// Is this an issue?
contactInfo[event.target.name] = event.target.value;
if (action === 'CHANGE') {
dispatch(updateContactInfo(contactInfo));
this.setState({ contactInfo });
} else {
this.setState({ contactInfo });
}
}
render() {
const { firstName, address, city } = this.state.contactInfo;
return (
<div>
<div>
<input placeholder=" " type="text" name='firstName' value={firstName} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>First & last name</span></div>
</div>
<div>
<input placeholder=" " type="text" name="address" value={address} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>Address</span></div>
</div>
<div>
<input placeholder=" " type="text" name="city" value={city} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>City</span></div>
</div>
</div>
)}
/ Reducer
const initialState = {
contactInformation: [],
}
export default function (state, action) {
state = state === undefined ? initialState : state;
switch (action.type) {
case 'CONTACT_INFO': {
state.contactInformation.test.info = payload;
return Object.assign({}, state, action.payload);
}
default: return state;
}
}
我不明白这样做的意义 使用 setState
在此
this.state = {
contactInfo: {...this.props}
}
onChangeInfo = ({target: {name, value}}, action) => {
const { dispatch } = this.props;
const contactInfo = {[name]: value};
if (action === 'CHANGE') {
dispatch(updateContactInfo(contactInfo));
}
}
例子
const { Component, useState, useEffect } = React;
const { bindActionCreators, combineReducers, createStore, applyMiddleware, compose } = Redux;
const { connect, Provider } = ReactRedux;
const initalState = {
contactInfo: {
firstName: '',
address: '',
city: ''
}
}
const reducer = (state = initalState, action) => {
switch (action.type) {
case 'CONTACT_INFO': {
const newState = {
...state,
contactInfo: {
...state.contactInfo,
...action.payload.contactInfo
}
};
return newState;
}
default: return state;
}
}
const reducers = combineReducers({
reducer
})
const store = createStore(
reducers
);
const updateContactInfo = (payload) => ({
type: 'CONTACT_INFO', payload
})
const mapStateToProps = state => {
return {
contactInfo: state.reducer.contactInfo
}
}
const mapDispatchToProps = dispatch => ({
updateContactInfo: payload => dispatch(updateContactInfo(payload))
})
class _App extends Component {
constructor(props) {
super(props);
this.state = {...this.props}
this.updateContactInfo = this.props.updateContactInfo;
}
static getDerivedStateFromProps (props, state) {
return {...props}
}
onChangeInfo ({target: {name, value}}, action) {
const contactInfo = { contactInfo: {[name]: value}};
if (action === 'CHANGE') {
this.updateContactInfo(contactInfo);
}
}
render() {
const { firstName, address, city } = this.state.contactInfo;
return <div>
<div>
<input placeholder=" " type="text" name='firstName' value={firstName} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>First & last name</span></div>
</div>
<div>
<input placeholder=" " type="text" name="address" value={address} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>Address</span></div>
</div>
<div>
<input placeholder=" " type="text" name="city" value={city} onChange={(e) => this.onChangeInfo(e, 'CHANGE')} required id="" />
<div className="placeholder"><span>City</span></div>
</div>
{JSON.stringify(this.state)}
</div>
}
}
const App = connect(mapStateToProps, mapDispatchToProps)(_App)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.10.1/polyfill.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/redux.js"></script>
<script src="https://unpkg.com/react-redux@latest/dist/react-redux.js"></script>
<div id="root"></div>
我建议你最好保持三个不同的动作,因为一个动作总是一个纯函数,而且是特定的操作。
export const firstName = (firstName) => ({
type : 'FIRST_NAME',
payload : firstName
});
export const address = (address) => ({
type : 'ADDRESS',
payload : address
});
export const city = (city) => ({
type : 'CITY',
payload : city
});
而且,在reducer中,根据action.type更新存储。
好问题。
在我给你答案之前,有几件事我必须指出。一般来说,在任何应用程序中都存在2种类型的状态:长期状态和短期(也就是短暂的)状态。Redux的目的是为你提供一个容器,用来放置你所有的长期状态,这些状态是你的应用程序中潜在的不同部分普遍关注的。
说到这里,我可以看到,你在你的应用程序中做的唯一一件事就是用用户输入更新状态。我敢打赌,当用户点击提交按钮时,你会使用该状态来做一些事情。如果你的情况是这样,那么输入的定义是短暂的,我将会 不 将输入状态完全放在Redux中。相反,我只会在用户提交表单时启动1个动作。
<form onSubmit={onSubmitHandler}>
<input name="name" type="text" />
<input name="hobby" type="text" />
<button type="submit" />
<form />
------
// this is slight pseudo-code, but hopefully you get the gist
const onSubmitHandler = (event) => {
const myFields = // get fields from event object.
dispatch({type: 'SOME-ACTION', fields: myFields})
}
我还建议你考虑改变你的动作建模方式。你可以看一下这个 视频 这是我的意思。