代码之家  ›  专栏  ›  技术社区  ›  Kayote

更新重做状态,然后在同一实例中获取更新的状态(&T)

  •  2
  • Kayote  · 技术社区  · 8 年前

    场景:

    我有一个回应 div 包含子图像的容器(CSS-宽度:33%)。不希望用户向下滚动,我想找出 div公司 ,这样我可以计算可以容纳的图像数(具有固定宽度和高度)。然后只渲染屏幕上适合的图像。

    我正在使用React(反应);恢复此应用程序。这是我想的逻辑,但它不起作用。

    _ Smart Component (subscribed to the Store)
    |___ `div` container (presentational component)
    |______ images (presentational components)
    

    我呈现“演示”组件,然后在 componentDidMount ,我发送了一个函数,该函数可以找出宽度&的高度 div公司 容器&用“image capacity”值更新Redux状态(可以在 div公司 容器)。

    在执行上述功能后立即执行,同时仍处于 组件DidMount ,我调度另一个函数,该函数应该 已更新 存储中的值(图像容量)&使用图像数据更新存储。

    想法是,当商店更新时,智能组件将重新呈现呈现组件( div公司 &图像)&因此,将进行第二轮重新渲染以显示图像。

    不幸的是,这是有缺陷的。传递给表示组件的道具是“预更新”存储值(0),因此当我运行调度第二个函数以使用图像更新存储时,它在道具中的“图像容量”值仍然为零(0)。

    我想知道这里要实现什么样的正确逻辑?

    如果代码更有意义,下面是表示组件代码:

    const PreviewTemParent = React.createClass({
        componentDidMount : function() {
            let elePreviewParent = ReactDOM.findDOMNode( this.refs.previewParent );
            previewTemParentAttr.width = elePreviewParent.clientWidth;
            previewTemParentAttr.height = elePreviewParent.clientHeight;
            this.props.findImgCapacity();
            this.temImgToShow( "body" );
        },
        temImgToShow : function( templateType ) {
            let pagination = this.props.previewTemState.get( "pagination" );
            let imgCapacity = this.props.previewTemState.get( "imgCapacity" );
            console.log( "%c     In `PreviewTemParent`, pag, imgCap & props are...", "color : gold", pagination, "; ", imgCapacity, "; ", this.props );
            this.props.temImgToShow( templateType, pagination, imgCapacity );
        },
    
        render : function() {
            return(
                <div
                 className = "previewParent"
                 ref = "previewParent">
                    <div className = "previewContainer">
                        { this.props.previewTemState.get( "temImg" ).map( ( imgObj ) => {
                            <PreviewTemImgContainer data = { imgObj } />;
                        } ) }
                    </div>
                </div>
            );
        }
    });
    

    编辑:

    应@pierrepinard_2的请求,我发布了一个详细的代码,希望能解释我的尝试。

    我尝试了一些方法,包括将“智能组件”添加到 <PreviewTemParent> &然后让父级计算尺寸。然而,在这种情况下,道具仍然没有更新,这是可以理解的,因为组件DidMount是在之后运行的 <预览TemParent> 已安装。

    以下是我根据@pierrepinard_2关于使用的建议尝试的解决方案 componentWillReceiveProps ,似乎没有被调用。

    C_PreviewTem父容器(智能组件)

    import { connect } from "react-redux";
    import { temImgToDisplayInContainer } from "../modcon/Actions.js";
    import PreviewTemParent from "../component/temContainer/PreviewTemParent.jsx";
    
    const mapStateToProps = ({ previewTemImgState }) => {
        return({
            previewTemState : previewTemImgState
        });
    };
    const mapDispatchToProps = ( dispatch ) => {
        return({
            temImgToDisplayInContainer : ( templateType, activePage ) => {
                dispatch( temImgToDisplayInContainer( templateType, activePage ) );
            }
        });
    };
    
    export const C_PreviewTemParent = connect( mapStateToProps, mapDispatchToProps )( PreviewTemParent );
    

    预览父组件

    const PreviewTemParent = React.createClass({
        componentDidMount : function() {
            this.props.temImgToDisplayInContainer( "body" );
        },
        componentWillReceiveProps : function( nextProps ) {
            console.log( "%c   componentWillReceiveProps is...", "color: green", nextProps );
        },
        render : function() {
            return(
                <div className = "previewParent">
                    <div className = "previewContainer">
                        { this.props.previewTemState.get( "temImg" ).map( ( imgObj ) => {
                            <PreviewTemImgContainer data = { imgObj } />;
                        } ) }
                    </div>
                </div>
            );
        }
    });
    

    动作创建者 请原谅冗长的代码:!

    export const temImgToDisplayInContainer = ( templateType, activePage ) => {
        // temImgCapacity finds out the number of images that can 
        // fit in the container based on the container's dynamic Width & Height.
        // in order to make the func reusable, activePage is an optional parameter
        // hence the `if`
        let temImgCapacity;
        if( activePage ){
            temImgCapacity = findImgCapacityInPreviewTem( false );
        } else {
            temImgCapacity = findImgCapacityInPreviewTem( true );
        }
        // `previewTemImgData` is a store of static data of all the images.
        // during development, this is being used instead of ajax calls etc
        // `temImgData` stores the data only for the 'templates' we are interested in
        let temImgData = previewTemImgData.get( templateType );
        let counter = 1;
        // `noOfTemplate` is how many images we will render
        let noOfTemplate = temImgCapacity.get( "imgCapacity" );
        let currentPage = activePage || temImgCapacity.get( "activePage" );
        // `maxCounter` is for pagination, which is the last template to store
        let maxCounter = currentPage * noOfTemplate;
        let temStartFrom = (( currentPage * noOfTemplate ) - noOfTemplate );    // what template start number.
        // get the tempales we are only interested in
        let filteredTemImgData = temImgData.filter( ( templateObj ) => {
            if (( counter <= maxCounter ) && ( counter >= temStartFrom )) {
                counter++;
                return( templateObj );
            }
        } );
        // merging the data from above first line 'temImgCapacity' & the filtered
        // temImgData
        let payloadData = filteredTemImgData.merge(( temImgCapacity ));
        return({
            type : CURRENT_TEM_IMG,
            payload : payloadData
        });
    };
    

    最后,减速器 :

    const previewTemImgState = ( state = initialPreviewTemState, action ) => {
        switch( action.type ) {
        case( FIND_IMG_CAPACITY_IN_PREVIEW_TEM ) :
            return(
                state.set( "imgCapacity", action.payload.imgCapacity )
            );
        case( RENDER_TEM_IMG ) :
            console.log( action.payload );
            var newState = state.set( "temImg", action.payload.temImg );
            console.log( "%c   previewTemImgState is...", "color : red", state.get( "temImg" ), " ; ", newState.get( "temImg" ) );
            return(
                state.set( "temImg", action.payload )
            );
        default :
            return state;
        }
    };
    
    1 回复  |  直到 8 年前
        1
  •  2
  •   pierrepinard_2    8 年前

    问题是当你打电话给 this.props.previewTemState 在里面 temImgToShow() ,状态对象引用仍然与的开头相同 componentDidMount() 执行,之前 this.props.findImgCapacity() 已调用。

    一种选择是只触发一个来自 组件DidMount() ,具有以下参数:width和height(用于计算图像容量)、templateType、pagination。然后,您将只获得一个具有所需状态的UI更新。

    如果您确实无法只触发一个操作来执行所有工作,那么您可以在 componentWillReceiveProps() 正如Honza Haering在评论中建议的那样:

    componentDidMount: function() {
        let elePreviewParent = ReactDOM.findDOMNode( this.refs.previewParent );
        previewTemParentAttr.width = elePreviewParent.clientWidth;
        previewTemParentAttr.height = elePreviewParent.clientHeight;
        this.props.findImgCapacity();
    },
    
    componentWillReceiveProps: function(nextProps) {
        let newImgCapacity = nextProps.previewTemState.get( "imgCapacity" );
        let oldImgCapacity = this.props.previewTemState.get( "imgCapacity" );
        if (newImgCapacity !== oldImgCapacity && newImgCapacity > 0) {
            let pagination = nextProps.previewTemState.get( "pagination" );
            nextProps.temImgToShow("body", pagination, newImgCapacity);
        }
    },
    

    或者,如果您使用 redux-thunk 中间件,您可以使用异步动作创建者,并承诺正确链接动作。如果你给我们你的行为准则,我可以告诉你怎么做。