Я только что немного изучил react-redux и застрял на таких проблемах, которые я не могу понять и исправить, по крайней мере, за 4 дня.
Первая проблема стоит и ее можно увидеть в консоли инспекторов (я использую Chrome).
У меня есть обработчик событий на <div> внутри компонента реакции. Он должен вызываться при событии onClick, но он срабатывает при каждой загрузке или перезагрузке сайта.
Во-вторых, стоит где-то рядом с функцией редуктора. В консоли (инструменты разработчика) мне сказано, что редукторы получили действие 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.info('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.info('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.info(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.info("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.info("tiles: "+state.forEach(value => console.info(value)));
}
const reducers = combineReducers({
tiles
});
export default reducers;
AppContainer.jsx
const mapStateToProps = (state) => {
return {
tiles: state.tiles
};
};
const mapDispatchToProps = (dispatch) => {
return {
toggle: id => {
// console.info(id);
dispatch(toggleTile(id));
}
};
};
class AppContainer extends Component {
constructor(props){
super(props);
}
componentDidMount(){
}
render() {
var prop = this.props;
console.info(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.info(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;



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Первую проблему можно решить, заменив
onClick = {this.toggleTile(value.id)}
с onClick = {(e) => this.toggleTile(value.id)} Первый оператор просто вызывает this.toggleTile (value.id) сразу и устанавливает возвращаемое значение для события OnClick.
Что касается второго, вы ничего не возвращаете из своего редуктора, поэтому состояние не определено.
if (i < 2){
console.info('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.info(i, value.opened, newOpen, openedTiles);
}
return newOpen, i;
});
}
Что это за return newOpen, i, он должен быть return newOpen, также, поскольку этот возврат находится в функции карты, вы также должны вернуть сопоставленный массив
так что используйте return state.map((value) => {
проблема, которая у вас есть, заключается в том, что вы фактически вызываете функцию внутри вашего 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.
Благодаря вам .. Похоже, что-то идет не так, но, в конце концов, это была моя вина, как вы, братаны, все видели .. Отсутствие внимания к деталям, что это такое ... Но также очень хороший ответ на первый вопрос, которым поделился @ PrinceHernandez. Все ваши советы помогли решить мои проблемы.