Redux не ведет себя правильно - PullRequest
0 голосов
/ 03 мая 2018

Я только что узнал немного о реакции-избыточности и застрял в таких проблемах, которые я не могу понять и исправить по крайней мере 4 дня.

  1. Первая проблема стоит и видна на консоли инспектора (я использую Chrome). У меня есть обработчик событий на <div> внутри реагирующего компонента. Он должен вызываться при событии onClick, но срабатывает при каждой загрузке или перезагрузке сайта.

  2. Во-вторых, стоит где-то рядом с функцией редуктора. В консоли (dev tools) говорится, что редукторы получили действие 'TOGGLE_TILE' и вернули undefined вместо объекта. Следует заметить, что редуктор успешно получает состояние, свойства действия и выполняет некоторые операции внутри, но в результате ничего нормального не возвращается.

    Код моего редуктора, действий, основного, контейнера, презентационных компонентов и функций. Пожалуйста, ответьте развернуто, как вы можете, я хочу понять, что не так и не делать эту ошибку внутри кода дважды.

ТАКЖЕ! Я использовал промежуточное программное обеспечение redux-thunk (для функциональных обратных вызовов внутри действий, вы знаете). Внутри у меня есть:

index.js - основной компонент

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

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

actions.js

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

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

tile.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

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

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;

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

проблема в том, что вы на самом деле вызываете функцию внутри вашего div, поэтому она будет срабатывать каждый раз, когда вы входите в представление, поэтому замените следующий код на showTiles()

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

к этому:

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

и на самом деле это должно исправить ошибку для пункта 2.

0 голосов
/ 03 мая 2018

Первая проблема может быть решена заменой

onClick={this.toggleTile(value.id)} с onClick={(e) => this.toggleTile(value.id)} Первый оператор просто вызывает this.toggleTile (value.id) немедленно и устанавливает возвращаемое значение в событие OnClick.

Что касается секунды, вы не возвращаете ничего из вашего редуктора, следовательно, состояние не определено.

       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;
            });
        }

Что это за return newOpen, i, это должно быть return newOpen, также, поскольку этот возврат находится в функции карты, вы должны также вернуть отображенный массив так что используйте return state.map((value) => {

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...