css操作在渲染之前发生,因此它不会有效

时间:2017-03-23 12:24:53

标签: ajax reactjs redux

我正在使用react和redux来完成我当前的项目。我有一个按钮,每当用户点击它时,它首先调用服务器并加载一些数据,然后操纵一些dom元素的CSS。 这是我的代码:

 var allClickableStories = document.getElementById("dummyClickStory" + this.props.story.id);

    $(allClickableStories).click(function () {

        if (!$("#" + this.id + " .expansion-handler").hasClass("show")) {

            var storyId = this.id.replace("dummyClickStory", "");
            thisRef.props.getStoryDetail(storyId, thisRef.props.channel);
            $("#" + this.id + " .expansion-handler").addClass("show");
            $("#" + this.id + " .cutline").addClass("show");
        }
    });

另外值得注意的是,componentDidMount中的上述代码确保首次渲染发生。但是,这并不能保证ajax调用(thisRef.props.getStoryDe​​tail)在css操作之前发生,这正是我被困在的地方。发生了什么是ajax调用被发送然后css操作触发但是ajax调用可能会返回并且渲染将发生并再次隐藏被操纵的dom元素。一种简单的方法来修复它是在jquery ajax调用中将asynch设置为false但不是一个好的解决方案那么我怎样才能确保第一个ajax调用完成并渲染发生然后进行css操作?

此处仅有更多信息,请参阅Action和reducer中的代码:

动作:

export function getStoryDetail(storyId,channel){
return dispatch => {
    $.ajax({
        url: "http://localhost:3003/json5.txt",
        dataType: 'json',
        cache: false,
        success: function(data) {
            var storyDetatil=[];
            for (var key in data) {
                storyDetatil.push(data[key]);
            }
            var storyDetailObj={"storyArray":storyDetatil,"storyId":storyId, "channel":channel};
            dispatch({
                type: "STORY_EXPANSION",
                payload: storyDetailObj

            });
        }.bind(this)
    });
};

}

减速机:

 case "STORY_EXPANSION":
        var tempStateExpansion = state.slice();
        if (action.payload.storyId > -1  && state[0].channel !=undefined) {
            for(var i=0;i<state.length;i++){
                if(state[i].channel.toLowerCase()===action.payload.channel.toLowerCase()){
                    for(var j=0;j<state[i].storiesSnippet.length;j++){
                        if(action.payload.storyId===state[i].storiesSnippet[j].id){
                            tempStateExpansion[i].storiesSnippet[j]=action.payload.storyArray[0];
                            break;
                        }
                    }
                    break;
                }
            }
        }
        else{
            tempStateExpansion[0].storiesSnippet[0]=action.payload.storyArray[0];
        }
        state=tempStateExpansion;

        break;

1 个答案:

答案 0 :(得分:0)

简而言之,你不能用React做到这一点。你正在使用jQuery来操作DOM,这基本上是与React相反的方法。 React为你操纵DOM。

你应该做的是拥有一个组件(你可以看一下内联样式:https://facebook.github.io/react/docs/dom-elements.html),它将根据更新的状态重新渲染。

  1. App呈现任何默认值并触发ajax请求。
  2. Ajax响应更新了redux存储,它通过connectmapStateToProps更新了在满足ajax请求时应该更改的组件的道具。
  3. 组件根据新状态重新渲染。渲染路径具有新样式(可能是内联的)
  4. 我建议在这里运行带有redux和React的TODO List示例:http://redux.js.org/docs/basics/UsageWithReact.html。您的Redux使用情况看起来没问题,但React是有问题的。

    以下是使用React组件的示例,该组件将根据redux状态的data属性重新渲染。它假定您将拥有一个应用程序范围的CSS,其中包含foobar CSS类的定义。

    import React from 'react';
    import { connect } from 'react-redux';
    
    class Example extends React.Component {
      render() {
        const { data } = this.props;
    
        // If data is present (render a div using CSS from class foo)
        // and put the data in the div asuming it's a string
        if (data) {
          return <div className='foo'>{ data }</div>;
        }
        // If data is not present (render a div using CSS from class bar)
        // Display No Content
        return <div className='bar'>No Content</div>;
      }
    }
    
    // Data is an object, but not required as initially it will be undefined
    Example.propTypes = {
      data: React.PropTypes.object
    };
    
    // Map redux state to react props
    const mapStateToProps = state => ({
      data: state.data
    });
    
    // Connect to redux store helper using our mapping function
    export default connect(mapStateToProps)(Example);