reactjs - Redux 无法处理来自 2 个输入的数据
问题描述
我正在尝试使用一个功能来控制我的组件的状态数据。我也在使用redux。但是 redux 有问题,或者我看不到我的错误。这是我的组件:
this.state = {
data: this.props.ui.users,
name: '',
email: ''
}
}
handleChange = (evt) => {
this.setState({ [evt.target.name]: evt.target.value });
}
componentWillReceiveProps = () => {
this.setState({
name: ''
})
}
render() {
return (
<div>
<form onSubmit={(e) => this.props.uiActions.addUser(e, this.state.name, this.state.email)}>
<input type="text"
name="name"
value={this.state.name}
onChange={this.handleChange}/>
</form>
</div>
)
}
}
一切正常。但是当我想添加另一个处理电子邮件输入的输入时,操作不会触发。我可以毫无问题地将 this.state.email 与我的数据一起传递,例如“某事”,但 redux 没有看到另一个输入。只需一个输入,一切都很好。不同之处在于我在第一个输入下面添加
<input type="text"
name="email"
value={this.state.email}
onChange={this.handleChange}/>
并且 redux 不会触发动作。下面是处理传递数据的操作:
export function addUser(e, name, email) {
return (dispatch, getState) => {
e.preventDefault()
console.log(email)
const { users } = getState().ui
dispatch({ type: UI_ACTIONS.ADD_USER, users:[...users, {id: users.length+1, name: name, email: email}] });
}
}
减速器:
export default (state = initialState, action) => {
switch (action.type) {
case UI_ACTIONS.SET_REPOS:
return { ...state, users: action.users };
case UI_ACTIONS.ADD_USER:
return {...state, users: action.users};
default:
return state;
}
};
我究竟做错了什么?在这里你可以找到我的仓库:https ://github.com/KamilStaszewski/crudapp/tree/develop/src
解决方案
这里有很多事情真的需要修改。您构建应用程序的方式是反模式(非标准/不良做法),随着应用程序变得更加动态,您会更加头疼。
需要考虑的几件事:
- 除非您使用大量嵌套的组件,否则您不需要 Redux(对于此示例,React 状态就足够了)
- 您应该将容器(Redux 连接函数/AJAX 请求)与组件(任何关心事物外观的函数)分开:https ://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
- 将操作保留
form
在表单的组件中(如e.preventDefault();
)并从内部使用 Redux 状态reducer
(您可以访问 reducer 中的 Redux 状态,因此对于addUser
操作,无需调用 Redux'sgetState();
)。 - 如果您只返回and ,则不需要
dispatch
a 。action
type
payload
- 永远是
.catch()
你的承诺。出于某种原因,有一种趋势是崭露头角的开发人员认为每个承诺都会解决并且永远不会抛出错误。不捕捉错误会破坏你的应用程序!
我已经着手重组了整个应用程序。我鼓励您解构它并遵循应用程序流程,然后接受您的项目并相应地修复它。
工作示例:https ://codesandbox.io/s/zn4ryqp5y4
动作/index.js
import { UI_ACTIONS } from "../types";
export const fetchUsers = () => dispatch => {
fetch(`https://jsonplaceholder.typicode.com/users`)
.then(resp => resp.json())
.then(data => dispatch({ type: UI_ACTIONS.SET_REPOS, payload: data }))
.catch(err => console.error(err.toString()));
};
/*
export const handleNameChange = value => ({
type: UI_ACTIONS.UPDATE_NAME,
val: value
})
*/
/*
export const handleEmailChange = value => ({
type: UI_ACTIONS.UPDATE_EMAIL,
val: value
})
*/
export const addUser = (name, email) => ({
type: UI_ACTIONS.ADD_USER,
payload: { name: name, email: email }
});
组件/App.js
import React from "react";
import UserListForm from "../containers/UserListForm";
export default ({ children }) => <div className="wrapper">{children}</div>;
组件/displayUserList.js
import map from "lodash/map";
import React from "react";
export default ({ users }) => (
<table>
<thead>
<tr>
<th>ID</th>
<th>USER</th>
<th>E-MAIL</th>
</tr>
</thead>
<tbody>
{map(users, ({ id, name, email }) => (
<tr key={email}>
<td>{id}</td>
<td>{name}</td>
<td>{email}</td>
</tr>
))}
</tbody>
<tfoot />
</table>
);
容器/UserListForm.js
import map from "lodash/map";
import React, { Component } from "react";
import { connect } from "react-redux";
import { addUser, fetchUsers } from "../actions/uiActions";
import DisplayUserList from "../components/displayUserList";
class Userlist extends Component {
state = {
name: "",
email: ""
};
componentDidMount = () => {
this.props.fetchUsers();
};
handleChange = evt => {
this.setState({ [evt.target.name]: evt.target.value });
};
handleSubmit = e => {
e.preventDefault();
const { email, name } = this.state;
if (!email || !name) return;
this.props.addUser(name, email);
this.setState({ email: "", name: "" });
};
render = () => (
<div style={{ padding: 20 }}>
<h1 style={{ textAlign: "center" }}>Utilizing Redux For Lists</h1>
<form style={{ marginBottom: 20 }} onSubmit={this.handleSubmit}>
<input
className="uk-input"
style={{ width: 300, marginBottom: 10 }}
type="text"
name="name"
placeholder="Add user's name..."
value={this.state.name}
onChange={this.handleChange}
/>
<br />
<input
className="uk-input"
style={{ width: 300, marginBottom: 10 }}
type="text"
name="email"
placeholder="Add user's email..."
value={this.state.email}
onChange={this.handleChange}
/>
<br />
<button className="uk-button uk-button-primary" type="submit">
Submit
</button>
</form>
<DisplayUserList users={this.props.users} />
</div>
);
}
export default connect(
state => ({ users: state.ui.users }),
{ addUser, fetchUsers }
)(Userlist);
减速器/index.js
import { routerReducer as routing } from "react-router-redux";
import { combineReducers } from "redux";
import { UI_ACTIONS } from "../types";
const initialState = {
users: [],
name: "",
email: ""
};
const uiReducer = (state = initialState, { payload, type }) => {
switch (type) {
case UI_ACTIONS.SET_REPOS:
return { ...state, users: payload };
case UI_ACTIONS.ADD_USER:
return {
...state,
users: [...state.users, { id: state.users.length + 1, ...payload }]
};
default:
return state;
}
};
const rootReducer = combineReducers({
ui: uiReducer,
routing
});
export default rootReducer;
根/index.js
import React from "react";
import { browserHistory, Router } from "react-router";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import { syncHistoryWithStore } from "react-router-redux";
import thunk from "redux-thunk";
import rootReducer from "../reducers";
import routes from "../routes";
// CONFIG REDUX STORE WITH REDUCERS, MIDDLEWARES, AND BROWSERHISTORY
const store = createStore(rootReducer, applyMiddleware(thunk));
const history = syncHistoryWithStore(browserHistory, store);
// APP CONFIG'D WITH REDUX STORE, BROWSERHISTORY AND ROUTES
export default () => (
<Provider store={store}>
<Router
onUpdate={() => window.scrollTo(0, 0)}
history={history}
routes={routes}
/>
</Provider>
);
路线/index.js
import React from "react";
import { IndexRoute, Route } from "react-router";
import App from "../components/App";
import UserListForm from "../containers/UserListForm";
export default (
<Route path="/" component={App}>
<IndexRoute component={UserListForm} />
</Route>
);
类型/index.js
export const UI_ACTIONS = {
UPDATE_NAME: "UPDATE_NAME",
INCREMENT_COUNT: "INCREMENT_COUNT",
SET_REPOS: "SET_REPOS",
ADD_USER: "ADD_USER",
UPDATE_NAME: "UPDATE_NAME",
UPDATE_EMAIL: "UPDATE_EMAIL"
};
export const TEST_ACTION = {
ACTION_1: "ACTION_1"
};
index.js
import React from "react";
import { render } from "react-dom";
import App from "./root";
import "uikit/dist/css/uikit.min.css";
render(<App />, document.getElementById("root"));
推荐阅读
- jwt - JWT:使用多个公钥创建令牌并使用一个私钥进行解码
- html - 包含“DOCTYPE html”时,带有视频标签的 Flex-Grow div 会增长以包含标题大小
- php - 如何在 codeigniter 中创建 10 分钟有效链接?
- angular - 如何使用angular7在ngx掩码中同时使用千位分隔符和小数点分隔符?
- django - Heroku Postgres - 我的生产数据库如何工作,即使未在 settings.py - Django 中列出?
- python - 用户输入的熊猫数据框
- typescript - SystemJS 没有导入
- fragment - 在片段中打开自定义选项卡
- facebook-opengraph - property="og:type" content="website" 和 property="og:type" content="article" 有什么区别
- python - 如何减少输出数量?