sto*_*one 30 reactjs react-redux
我在react-redux网站上遇到了一个重复模式:一个组件显示来自web api的数据,它应该在加载时自动填充,无需任何用户交互.
我想从容器组件启动异步提取,但据我所知,唯一的方法是从显示组件中的生命周期事件.这似乎使得无法将所有逻辑放在容器中,只使用哑无状态功能组件进行显示.
这意味着我不能将无状态功能组件用于任何需要异步数据的组件.这似乎不对.
似乎"正确"的方法是以某种方式从容器启动异步调用.然后,当调用返回时,状态将被更新,容器将获得新状态,然后将其传递给其无状态组件mapStateToProps().
进行异步调用mapStateToProps和mapDispatchToProps(我的意思是实际调用异步函数,而不是将其作为属性返回)没有意义.
所以我最终做的是将异步调用放在一个refreshData()公开的函数中mapDispatchToProps(),然后从两个或多个React生命周期方法中调用它:componentDidMount and componentWillReceiveProps.
有没有一种干净的方法来更新redux存储状态而不在每个需要异步数据的组件中放入生命周期方法调用?
我是否应该将这些调用放在组件层次结构的更高位置(从而减少此问题的范围,因为只有"顶级"组件才需要监听生命周期事件)?
就这样,我对connect()ed容器组件的意思没有任何混淆,这是一个非常简单的例子:
import React from 'react';
import { connect } from 'react-redux';
import {action} from './actions.js';
import MyDumbComponent from './myDumbComponent.jsx';
function mapStateToProps(state)
{
return { something: state.xxxreducer.something };
}
function mapDispatchToProps(dispatch)
{
return {
doAction: ()=>{dispatch(action())}
};
}
const MyDumbComponentContainer = connect(
mapStateToProps,
mapDispatchToProps
)(MyDumbComponent);
// Uh... how can I hook into to componentDidMount()? This isn't
// a normal React class.
export default MyDumbComponentContainer;
Run Code Online (Sandbox Code Playgroud)
Jamie Dixon写了一个包来做这个!
https://github.com/JamieDixon/react-lifecycle-component
用法如下所示:
const mapDispatchToProps = {
componentDidMount: getAllTehDatas
}
...
export default connectWithLifecycle(mapStateToProps, mapDispatchToProps)(WrappedComponent)
Run Code Online (Sandbox Code Playgroud)
编辑 使用钩子,您现在可以在无状态功能组件中实现生命周期回调.虽然这可能无法直接解决问题中的所有问题,但它也可能解决了一些想要做最初提议的事情的原因.
编辑到原始答案 在评论讨论和思考之后,这个答案更具探索性,可以作为对话的一部分.但我不认为这是正确的答案.
原始答案
在Redux站点上有一个示例,显示您不必同时执行mapStateToProps和mapDispatchToProps.你可以利用connect道具的强大功能,使用一个类并在哑组件上实现生命周期方法.
在该示例中,连接调用甚至在同一文件中,甚至不导出哑组件,因此对于组件的用户来说它看起来是相同的.
我可以理解不想从显示组件发出异步调用.我认为从那里发出异步调用和调度一个动作之间存在区别,该动作通过thunk将异步调用的发布移动到动作中(甚至更多地与React代码分离).
作为一个例子,这里是一个启动画面组件,我想在显示组件安装时执行一些异步操作(如资源预加载):
SplashContainer.js
import { connect } from 'react-redux'
import Splash from '../components/Splash'
import * as actions from '../actions'
const mapStateToProps = (state) => {
return {
// whatever you need here
}
}
const mapDispatchToProps = (dispatch) => {
return {
onMount: () => dispatch(actions.splashMount())
}
}
const SceneSplash = connect(
mapStateToProps,
mapDispatchToProps
)(Splash)
export default SceneSplash
Run Code Online (Sandbox Code Playgroud)
Splash.js
import React from 'react'
class Splash extends React.Component {
render() {
return (
<div className="scene splash">
<span className="fa fa-gear fa-spin"></span>
</div>
)
}
componentDidMount() {
const { onMount } = this.props
onMount()
}
}
export default Splash
Run Code Online (Sandbox Code Playgroud)
您可以看到调度发生在连接的容器中,您可以想象在actions.splashMount()调用中我们发出异步http请求或通过thunks或promises 执行其他异步操作.
编辑澄清
请允许我尝试捍卫这种方法.我重新阅读了这个问题,并不是100%肯定我正在解决它之后的主要问题,但请耐心等待.如果我还没有完全按计划进行,我可以在下面修改一个可能更接近标记的方法.
"它应该在负载上填充" - 上面的例子实现了这一点
"我想从容器启动异步提取" - 在示例中,它不是从显示组件或容器启动的,而是从异步操作启动的
"这似乎使得无法将所有逻辑放入容器中" - 我认为您仍然可以在容器中添加任何其他逻辑.如上所述,数据加载代码不在显示组件(或容器)中,而是在异步操作创建器中.
"这意味着我不能为任何需要异步数据的组件使用无状态功能组件." - 在上面的例子中,显示组件是无状态和功能的.唯一的链接是调用回调的生命周期方法.它不需要知道或关心回调的作用.这不是显示组件试图成为异步数据获取的所有者的情况 - 它只是让处理它的代码知道特定事件何时发生.
到目前为止,我试图证明给出的例子如何满足问题的要求.也就是说,如果您所拥有的是显示组件,即使是间接回调,也绝对不包含与异步数据加载相关的代码 - 也就是说,它唯一的链接就是通过它所传递的道具来消耗该数据.远程数据下来,然后我会建议这样的事情:
SplashContainer.js
import { connect } from 'react-redux'
import Splash from '../components/Splash'
import * as actions from '../actions'
const mapStateToProps = (state) => {
return {
// whatever you need here
}
}
const mapDispatchToProps = (dispatch) => {
dispatch(actions.splashMount())
return {
// whatever else here may be needed
}
}
const SceneSplash = connect(
mapStateToProps,
mapDispatchToProps
)(Splash)
export default SceneSplash
Run Code Online (Sandbox Code Playgroud)
Splash.js
import React from 'react'
class Splash extends React.Component {
// incorporate any this.props references here as desired
render() {
return (
<div className="scene splash">
<span className="fa fa-gear fa-spin"></span>
</div>
)
}
}
export default Splash
Run Code Online (Sandbox Code Playgroud)
通过在mapDispatchToProps中调度操作,您可以让该操作的代码完全驻留在容器中.实际上,只要实例化容器,就会启动异步调用,而不是等待连接的显示组件旋转并挂载.但是,如果在显示组件的componentDidMount()触发之前无法启动异步调用,我认为您本身就必须拥有像我的第一个示例中那样的代码.
我实际上没有测试过第二种方法,看看react或redux是否会抱怨它,但它应该有效.您可以访问调度方法,并且应该可以毫无问题地调用它.
老实说,第二个例子,虽然从显示组件中删除了与async动作相关的所有代码,但有点让我感到有点滑稽,因为我们正在以同名方式执行非映射派对的事情.功能.并且容器实际上没有componentDidMount来运行它.所以我对它有点畏缩,并倾向于第一种方法.它在"感觉正确"的意义上并不干净,但它处于"简单的单线"感.
| 归档时间: |
|
| 查看次数: |
5266 次 |
| 最近记录: |