简体   繁体   English

Redux行为不正确

[英]Redux doesn't behave correctly

I just learned a little of react-redux and stuck at such problems I cannot understand and fix at least 4 days long. 我刚刚学到了一些react-redux并且遇到了我无法理解的问题并且至少坚持了4天。

  1. First of the problem stands and can be seen at inspectors console (I use Chrome). 首先是问题,可以在检查员控制台看到(我使用Chrome)。 I have event handler at <div> inside react component. 我在<div>里面有反应组件的事件处理程序。 It have to be called at onClick event but it triggers at each load or reload of site. 它必须在onClick事件中调用,但它会在每次加载或重新加载站点时触发。

  2. Second, stands somewhere near reducer's function. 其次,站在减速器功能附近。 It says me in console (dev tools) that reducers received action 'TOGGLE_TILE' and returned undefined instead of object. 它告诉我在控制台(开发工具)中,reducers收到动作'TOGGLE_TILE'并返回undefined而不是object。 Should notice that reducer successfully receives state, action properties and makes some operations inside but as result nothing normal returnes. 应该注意到reducer成功接收状态,动作属性并在内部进行一些操作但结果没有正常的返回。

    The code of my reducer, actions, main, container, presentation components and functions provide. 我的reducer,actions,main,container,presentation组件和函数的代码提供了。 Please answer expanded as you can, i want to understand whats wrong and not make this mistake inside code twice. 请尽可能地回答扩展,我想了解什么是错误的,并且不要在代码中两次犯这个错误。

ALSO! 也! I using redux-thunk middleware (to functional callbacks inside actions, you know). 我使用redux-thunk中间件(对于动作中的功能回调,你知道)。 Inside i have: 里面我有:

index.js - main component index.js - 主要组件

const store = createStore(reducer, applyMiddleware(thunk));

ReactDOM.render(
    <Provider store={store}>
        <AppContainer />
    </Provider>, 
    document.getElementById('root')
);
registerServiceWorker();

actions.js actions.js

export function toggle(id){
    return{
        type: 'TOGGLE_TILE',
        id
    };
}

export function toggleTile(id){
    return dispatch => {
        console.log('toggling');
        dispatch(toggle(id));
    };
}

tiles.js - Reducer tiles.js - 减速器

var i = 0;

function tiles(state = tilesContainer, action){
    var openedTiles = [];
    switch (action.type) {
        case 'TOGGLE_TILE':
            if(i < 2){  
                console.log('i: '+i);  
                state.map((value) => {
                    var newOpen;
                    if(!value.opened && action.id === value.id){  
                        newOpen = Object.assign({}, value, {
                            opened: !value.opened
                        });  
                        openedTiles.push(newOpen);
                        i++;
                        console.log(i, value.opened, newOpen, openedTiles);
                    }
                    return newOpen, i;
                });
            }else if(i === 2){
                var curr, prev;
                openedTiles.map((value) => {
                    if(!prev){
                        prev = value;
                    }else{
                        curr = value;
                        console.log("Prev and curr: "+prev, curr);
                        if(curr.name === prev.name){
                            var currRes = Object.assign({}, curr, {
                                disappeared: !curr.disappeared
                            });
                            var prevRes = Object.assign({}, prev, {
                                disappeared: !prev.disappeared
                            });
                            return {currRes, prevRes}; 
                        } else {
                            let currRes = Object.assign({}, curr, {
                                opened: !curr.opened
                            });
                            let prevRes = Object.assign({}, prev, {
                                opened: !prev.opened
                            })
                            return currRes, prevRes;
                        }
                    }
                });
            }else{
                return state;
            }
        default:
            return state;
    }
    console.log("tiles: "+state.forEach(value => console.log(value)));
}



const reducers = combineReducers({
    tiles
});

export default reducers;

AppContainer.jsx AppContainer.jsx

const mapStateToProps = (state) => {
  return {
    tiles: state.tiles
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    toggle: id => {
      // console.log(id);
      dispatch(toggleTile(id));
    }
  };
};


class AppContainer extends Component {
  constructor(props){
    super(props);
  }
  componentDidMount(){

  }
  render() {
    var prop = this.props;
    console.log(prop);
    return (
      <div>
        <AppView prop={prop} />
      </div>
    );
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(AppContainer);

AppView.js AppView.js

class AppView extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            tiles: this.props.prop.tiles,
        };
        this.showTiles = this.showTiles.bind(this);
        this.defineRatio = this.defineRatio.bind(this);
        this.toggleTile = this.toggleTile.bind(this);
    }
    componentDidMount(){
        this.defineRatio();

    }
    componentWillMount(){

    }
    defineRatio(){
        var imgClass;
        let tile = document.querySelectorAll('img');
        tile.forEach((value) => {
            var imgSrc, imgW, imgH;
            function defineImage(imgSrc){
                var img = new Image();
                img.src = imgSrc;
                img.onload = function() {   
                    return {
                        src:imgSrc,
                        width:this.width,
                        height:this.height};
                    };
                return img;
            }
            var x = defineImage(value.src);
            x.addEventListener('load',function(){
                imgSrc = x.src;
                imgW = x.width;
                imgH = x.height;
                // console.log(value.src, imgW, imgH);
                var imgClass = (imgW / imgH > 1) ? 'wide' : 'tall';
                value.classList += imgClass;
            });
        });
    }
    toggleTile(id){
        this.props.prop.toggle(id);
    }
    showTiles(){
        const boxElems = this.state.tiles.map((value, index) => {
            var styles = {background: 'black'};
            var tileState = value.opened ? '' : styles;
            var imgState = value.opened ? 'opened ' : 'closed ';
            var elem = <img key={value.id} src={value.src} alt="" className={imgState} />;
            var boxElem = <div style={tileState} className="tile-box " onClick={this.toggleTile(value.id)} key={index}>{elem}</div>;
            return boxElem;
        });
        return boxElems;
    }
    render(){
        var tiles = this.showTiles();
        return (
            <div className="tiles-box">
                <div className="tiles">
                    {tiles}
                </div>
            </div>
        );
    }
}

export default AppView;

First problem can be solved by replacing 第一个问题可以通过替换来解决

onClick={this.toggleTile(value.id)} with onClick={(e) => this.toggleTile(value.id)} First statement is just invoking this.toggleTile(value.id) immediately and setting the return value to OnClick event. onClick={this.toggleTile(value.id)} with onClick={(e) => this.toggleTile(value.id)}第一个语句只是立即调用this.toggleTile(value.id)并将返回值设置为OnClick事件。

Regarding second you are not returning any thing from your reducer , hence state is undefined. 关于秒,你没有从你的减速器返回任何东西,因此状态是未定义的。

       if(i < 2){  
            console.log('i: '+i);  
            state.map((value) => {
                var newOpen;
                if(!value.opened && action.id === value.id){  
                    newOpen = Object.assign({}, value, {
                        opened: !value.opened
                    });  
                    openedTiles.push(newOpen);
                    i++;
                    console.log(i, value.opened, newOpen, openedTiles);
                }
                return newOpen, i;
            });
        }

What is this return newOpen, i it should be return newOpen , also as this return is in a map function you have to return the mapped array as well so use return state.map((value) => { 什么是return newOpen, i应该return newOpen ,同样这个返回是在map函数中你必须返回映射数组,所以使用return state.map((value) => {

the problem that you have is that you are actually calling the function inside your div , thus it will get triggered each time you enter the view, so replace the following code on your showTiles() 您遇到的问题是您实际上是在div调用函数,因此每次进入视图时都会触发它,因此请在showTiles()上替换以下代码

var boxElem = <div style={tileState} className="tile-box " onClick={this.toggleTile(value.id)} key={index}>{elem}</div>;

to this: 对此:

var boxElem = <div style={tileState} className="tile-box " onClick={e => this.toggleTile(value.id)} key={index}>{elem}</div>;

and actually this should fix the error for the point 2. 实际上这应该修复第2点的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM