Javascript React 和 Redux:connect() 到多个组件和最佳实践
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35032204/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
React & Redux : connect() to multiple components & best practices
提问by Armelias
I'm working on my first React/Redux project and I have a little question. I've read the documentation and watched the tutorials available at https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist.
我正在做我的第一个 React/Redux 项目,我有一个小问题。我已阅读文档并观看了https://egghead.io/lessons/javascript-redux-generate-containers-with-connect-from-react-redux-visibletodolist 上提供的教程。
But I still have one question. It's about a login page. So I have a presentational component named LoginForm :
但我还有一个问题。这是关于登录页面。所以我有一个名为 LoginForm 的展示组件:
components/LoginForm.js
组件/LoginForm.js
import { Component, PropTypes } from 'react'
class LoginForm extends Component {
render () {
return (
<div>
<form action="#" onSubmitLogin={(e) => this.handleSubmit(e)}>
<input type="text" ref={node => { this.login = node }} />
<input type="password" ref={node => { this.password = node }} />
<input type="submit" value="Login" />
</form>
</div>
)
}
handleSubmit(e) {
e.preventDefault();
this.props.onSubmitLogin(this.login.value, this.password.value);
}
}
LoginForm.propTypes = {
onSubmitLogin: PropTypes.func.isRequired
};
export default LoginForm;
And a container component named Login which pass data to my component. Using react-redux-router, I call this container (and not the presentationnal component) :
还有一个名为 Login 的容器组件,它将数据传递给我的组件。使用 react-redux-router,我调用这个容器(而不是presentationnal 组件):
containers/Login.js
容器/Login.js
import { connect } from 'react-redux'
import { login } from '../actions/creators/userActionCreators'
import LoginForm from '../components/LoginForm'
const mapDispatchToProps = (dispatch) => {
return {
onSubmitLogin: (id, pass) => dispatch(login(id, pass))
}
};
export default connect(null, mapDispatchToProps)(LoginForm);
As you can see, I'm using the connect
method provide by redux to create my container.
如您所见,我正在使用connect
redux 提供的方法来创建我的容器。
My question is the following one :
我的问题是以下一个:
If I want my Login container to use multiple views (for example : LoginForm and errorList to display errors), I need to do it by hand (without connect because connect take only one argument). Something like :
如果我希望我的登录容器使用多个视图(例如:LoginForm 和 errorList 来显示错误),我需要手动完成(不连接,因为连接只接受一个参数)。就像是 :
class Login extends Component {
render() {
return (
<div>
<errorList />
<LoginForm onSubmitLogin={ (id, pass) => dispatch(login(id, pass)) } />
</div>
)
}
}
Is it a bad practice ? Is it better to create another presentational component (LoginPage) which use both errorList and LoginForm and create a container (Login) which connect
to LoginPage ?
这是一种不好的做法吗?创建另一个同时使用 errorList 和 LoginForm 的展示组件 (LoginPage) 并创建一个容器 (Login)connect
到 LoginPage 是否更好?
EDIT:If I create a third presentational component (LoginPage), I'll have to pass data twice. Like this : Container -> LoginPage -> LoginForm & ErrorList
.
Even with context, it don't seems to be the way to go.
编辑:如果我创建第三个展示组件 (LoginPage),我将不得不传递数据两次。像这样:Container -> LoginPage -> LoginForm & ErrorList
。即使有上下文,它似乎也不是要走的路。
回答by Nick Ball
I think that what you have in your second example is very close. You can create just one container component that's connected and render multiple presentational components.
我认为您在第二个示例中的内容非常接近。您可以只创建一个连接的容器组件并呈现多个展示组件。
In your first example, there actually isn'ta separate container component:
在您的第一个示例中,实际上没有单独的容器组件:
import { connect } from 'react-redux'
import { login } from '../actions/creators/userActionCreators'
import LoginForm from '../components/LoginForm'
const mapDispatchToProps = (dispatch) => {
return {
onSubmitLogin: (id, pass) => dispatch(login(id, pass))
}
};
// `LoginForm` is being passed, so it would be the "container"
// component in this scenario
export default connect(null, mapDispatchToProps)(LoginForm);
Even though it's in a separate module, what you're doing here is connecting your LoginForm
directly.
即使它在一个单独的模块中,你在这里所做的是LoginForm
直接连接你的。
Instead, what you can do is something like this:
相反,你可以做的是这样的:
containers/Login.js
容器/Login.js
import { connect } from 'react-redux'
import { login } from '../actions/creators/userActionCreators'
import LoginForm from '../components/LoginForm'
import ErrorList from '../components/ErrorList'
class Login extends Component {
render() {
const { onSubmitLogin, errors } = this.props;
return (
<div>
<ErrorList errors={errors} />
<LoginForm onSubmitLogin={onSubmitLogin} />
</div>
)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSubmitLogin: (id, pass) => dispatch(login(id, pass))
}
};
const mapStateToProps = (state) => {
return {
errors: state.errors
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Login);
Note that the Login
component is now being passed to connect
, making it the "container" component and then both the errorList
and LoginForm
can be presentational. All of their data can be passed via props by the Login
container.
请注意,该Login
组件现在被传递给connect
,使其成为“容器”组件,然后errorList
和LoginForm
都可以是展示性的。它们的所有数据都可以通过Login
容器通过 props 传递。
回答by Danilo Castro
I truly believe that you need to build all your components as Presentational Components. At the moment you need a Container Component, you might use {connect} over one of the existing Presentational and convert into a Container one.
我真的相信您需要将所有组件构建为演示组件。在您需要一个容器组件的那一刻,您可以在现有的 Presentational 之一上使用 {connect} 并转换为一个容器。
But, that is only my view with short experience in React so far.
但是,这只是我目前在 React 方面经验不足的看法。