我刚刚学到了一些react-redux并且遇到了我无法理解的问题并且至少坚持了4天。
首先出现问题,可以在检查员控制台看到(我使用的是Chrome)。
我在反应组件内的<div>
处有事件处理程序。它必须在onClick
事件中调用,但它会在每次加载或重新加载站点时触发。
其次,站在减速机功能附近。它告诉我在控制台(开发工具)中减速器接收到的动作&#39; TOGGLE_TILE&#39;并返回undefined而不是object。应该注意到reducer成功接收状态,动作属性并在里面进行一些操作,但结果没有正常的返回。
我的reducer,actions,main,container,presentation组件和函数的代码提供。请尽量回答扩展,我想了解什么是错误的,不要在代码中犯两次错误。
也!我使用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));
};
}
tiles.js - Reducer
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;
答案 0 :(得分:1)
第一个问题可以通过替换
来解决 onClick={this.toggleTile(value.id)}
with onClick={(e) => this.toggleTile(value.id)}
第一个语句只是立即调用this.toggleTile(value.id)并将返回值设置为OnClick事件。
关于秒,你没有从你的reducer返回任何东西,因此状态是未定义的。
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
是什么,因为这个返回是在map函数中你必须返回映射数组
所以使用return state.map((value) => {
答案 1 :(得分:1)
您遇到的问题是您实际上是在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点的错误。