Хорошо, у меня есть скребок для головы, с которым мне нужно немного помочь. Установка заключается в том, что у меня есть приложение React / Redux со страницей категорий, которая читает список категорий из API, а затем выводит их список. Эта часть отлично работает. Я пытаюсь передать обработчик событий каждому дочернему компоненту категории, который при нажатии отправляет действие, которое переключает состояние компонента, т. Е. Если категория выбрана и нажата, она будет " снимите флажок «it» (что фактически означает удаление записи из таблицы базы данных с именем user_category) и, если она не выбрана, «выберет» эту категорию для этого пользователя (добавьте запись в таблицу user_category).
Итак, у меня есть обработчик onclick (handleCatClick), который должен в конечном итоге передавать categoryId и userId для выполнения этих операций. К сожалению, я обнаружил, что, хотя эти аргументы передаются функции, они в конечном итоге не определены. Поэтому я не уверен, правильно ли я передаю эту функцию или что именно пропустил.
Все работает, кроме этого - может быть, вы можете помочь мне определить проблему; -)
Нажмите здесь, чтобы посмотреть макет базы данных
Нажмите здесь, чтобы посмотреть, как выглядит страница категории
Применимые страницы в моем приложении:
Архитектура выглядит в основном так:
/views/[Categories]
- index.js (wrapper for the Categories Component)
- CategoriesComponent.jsx (should be self-explanatory)
[duck]
- index.js (just imports a couple of files & ties stuff together)
- operations.js (where my handleCatClick() method is)
- types.js (Redux constants)
- actions.js (Redux actions)
- reducers.js (Redux reducers)
[components]
[Category]
- index.jsx (the individual Category component)
/ views / index.js (оболочка главной страницы категории)
import { connect } from 'react-redux';
import CategoriesComponent from './CategoriesComponent';
import { categoriesOperations } from './duck'; // operations.js
const mapStateToProps = state => {
// current state properties passed down to LoginComponent (LoginComponent.js)
const { categoryArray } = state.categories;
return { categoryArray }
};
const mapDispatchToProps = (dispatch) => {
// all passed in from LoginOperations (operations.js)
const loadUserCategories = () => dispatch(categoriesOperations.loadUserCategories());
const handleCatClick = () => dispatch(categoriesOperations.handleCatClick());
return {
loadUserCategories,
handleCatClick
}
};
const CategoriesContainer = connect(mapStateToProps,mapDispatchToProps)(CategoriesComponent);
export default CategoriesContainer;
/ views / CategoriesComponent.jsx (слой отображения для представления Categories)
import React from 'react';
import {Row,Col,Container, Form, Button} from 'react-bootstrap';
import {Link} from 'react-router-dom';
import './styles.scss';
import Category from './components/Category';
import shortid from 'shortid';
class CategoriesComponent extends React.Component {
constructor(props) {
super(props);
this.loadUserCats = this.props.loadUserCategories;
this.handleCatClick = this.props.handleCatClick;
}
componentWillMount() {
this.loadUserCats();
}
render() {
return (
<Container fluid className="categories nopadding">
<Row>
<Col xs={12}>
<div className="page-container">
<div className="title-container">
<h4>Pick your favorite categories to contine</h4>
</div>
<div className="content-container">
<div className="category-container">
{
this.props.categoryArray.map((item) => {
return <Category className="category" handleClick={this.props.handleCatClick} key={shortid.generate()} categoryData={item} />
})
}
</div>
</div>
</div>
</Col>
</Row>
</Container>
)
}
}
export default CategoriesComponent
/ views / Categories / components / index.jsx (отдельный компонент категории)
import React from 'react';
import {Row,Col,Container, Form, Button} from 'react-bootstrap';
import './styles.scss';
import Img from 'react-image';
class Category extends React.Component {
constructor(props) {
super(props);
this.state = {
categoryName: this.props.categoryData.category_name,
categoryImg: this.props.categoryData.category_img,
categoryId: this.props.categoryData.category_id,
userId: this.props.categoryData.user_id,
selected: this.props.categoryData.user_id !== null,
hoverState: ''
}
this.hover = this.hover.bind(this);
this.hoverOff = this.hoverOff.bind(this);
this.toggleCat = this.toggleCat.bind(this);
}
toggleCat() {
// the onClick handler that is supposed to
// pass categoryId and userId. When I do a
// console.log(categoryId, userId) these two values
// show up no problem...
const {categoryId, userId} = this.state;
this.props.handleClick(categoryId, userId);
}
hover() {
this.setState({
hoverState: 'hover-on'
});
}
hoverOff() {
this.setState({
hoverState: ''
});
}
render() {
const isSelected = (baseCat) => {
if(this.state.selected) {
return baseCat + " selected";
}
return baseCat;
}
return (
<div className={"category" + ' ' + this.state.hoverState} onClick={this.toggleCat} onMouseOver={this.hover} onMouseOut={this.hoverOff}>
<div className={this.state.selected ? "category-img selected" : "category-img"}>
<Img src={"/public/images/category/" + this.state.categoryImg} className="img-fluid" />
</div>
<div className="category-title">
<h5 className={this.state.selected ? "bg-primary" : "bg-secondary"}>{this.state.categoryName}</h5>
</div>
</div>
);
}
}
export default Category;
/ views / Categories / duck / operations.js (где я все это связываю)
// operations.js
import fetch from 'cross-fetch';
import Actions from './actions';
import Config from '../../../../config';
const loadCategories = Actions.loadCats;
const selectCat = Actions.selectCat;
const unSelectCat = Actions.unSelectCat;
const localState = JSON.parse(localStorage.getItem('state'));
const userId = localState != null ? localState.userSession.userId : -1;
const loadUserCategories = () => {
return dispatch => {
return fetch(Config.API_ROOT + 'usercategories/' + userId)
.then(response => response.json())
.then(json => {
dispatch(loadCategories(json));
});
}
}
const handleCatClick = (categoryId, categoryUserId) => {
// HERE IS WHERE I'M HAVING A PROBLEM:
// for whatever reason, categoryId and categoryUserId
// are undefined here even though I'm passing in the
// values in the Category component (see 'toggleCat' method)
var params = {
method: categoryUserId !== null ? 'delete' : 'post',
headers: {'Content-Type':'application/json'},
body: JSON.stringify(
{
"category_id": categoryId,
user_id: categoryUserId !== null ? categoryUserId : userId
}
)
};
const toDispatch = categoryUserId !== null ? unSelectCat : selectCat;
return dispatch => {
return fetch(Config.API_ROOT + 'usercategories/', params)
.then(response => response.json())
.then(json => {
dispatch(toDispatch(json));
});
}
}
export default {
loadUserCategories,
handleCatClick
}
Проблема, с которой я столкнулся:
Так что я думаю, что я либо неправильно ссылаюсь на handleCatClick, либо я почему-то неправильно передаю categoryId и userId, чтобы, когда он наконец достигнет handleCatClick (categoryId, categoryUserId) в operations.js , это заканчивается как неопределенное. Это, наверное, что-то простое, но я не могу это заметить. ПРИМЕЧАНИЕ. Я не включил файлы, такие как types.js или redurs.js, потому что они, похоже, выходят за рамки проблемы, но если они вам нужны, пожалуйста, дайте мне знать. Заранее спасибо за помощь!