У меня есть компонент контейнера, который извлекает данные в Rails API, но не может успешно выполнить итерацию по этим данным, не получив следующую ошибку:
TypeError: this.state.dryRedBottles.map is not a function
Это было вызвано следующим кодом;
render() {
let searchResults = this.state.dryRedBottles.map((bottle) => <SearchResults key={bottle} name={bottle}/>)
Как вы можете видеть в приведенном выше коде, я устанавливаю переменную, равную итерации для this.state.dryRedBottles, которая должна сопоставлять каждый объект бутылки с компонентом представления SearchResults.
Я также создал функцию generateSearchResults для отладки this.props и this.state.this.state.dryRedBottles по умолчанию является пустым массивом, но он обновляется и становится массивом объектов.Поскольку итераторы, такие как .map или .forEach, работают только с массивами, я попытался смягчить это на своем сервере Rails;
def create
@wine_bottles = WineBottle.all
if params[:dryRedBottles][:fetchingRedDry] == true
@red_dry_bottles = []
@wine_bottles.each do |bottle|
if (bottle.w_type == 'red') & (bottle.dry == true)
bottle = [bottle] if !bottle.is_a?(Array)
@red_dry_bottles.push(bottle)
end
end
render json: @red_dry_bottles
else
nil;
end
end
Я убедился, что каждый объект JSON был помещен внутрь массива, так что, по крайней мере, так.state.dryRedBottles вернет это;[[{}], [{}], [{}]].
Мой вопрос: что является причиной этой ошибки? Какие обходные пути можно использовать для успешного использованияsearchResults?
Ниже мой контейнерный компонент во всей полноте;
class Red extends Component {
constructor(props) {
super(props);
this.state = {
// helps monitor toggling
redDryClick: false,
redBothClick: false,
redSweetClick: false,
fetchingRedDry: false,
fetchingRedSweet: false,
dryRedBottles: []
};
};
handleSweetRequest = (event) => {
event.preventDefault();
this.setState(prevState => ({
redDryClick: !prevState.redDryClick,
redBothClick: !prevState.redBothClick
}));
}
handleDryRequest = (event) => {
event.preventDefault();
this.setState(prevState => ({
redSweetClick: !prevState.redSweetClick,
redBothClick: !prevState.redBothClick,
fetchingRedDry: !prevState.fetchingRedDry
}));
}
componentDidUpdate(){
if (this.state.fetchingRedDry === true) {
let redDryState = Object.assign({}, this.state);
this.props.fetchDryReds(redDryState);
// this.props.dryRedBottles.length > this.state.dryRedBottles.length
if (this.props.dryRedBottles !== this.state.dryRedBottles ) {
this.setState({ dryRedBottles: this.props.dryRedBottles });
}
}
debugger;
}
handleBothRequest = (event) => {
event.preventDefault();
this.setState(prevState => ({
redDryClick: !prevState.redDryClick,
redSweetClick: !prevState.redSweetClick
}));
}
generateSearchResults = () => {
debugger;
if ( Array.isArray(this.props.dryRedBottles) ) {
this.props.dryRedBottles.map((bottle) => {
debugger;
return bottle;
})
}
}
render() {
let searchResults = this.state.dryRedBottles.map((bottle) => <SearchResults key={bottle} name={bottle}/>)
return (
<div>
<h2>Welcome to... Red</h2>
<FormControlLabel
control={
<Switch
// configuring @material-ui Switch componanet
value="hidden"
color="primary"
id="redSweet"
disableRipple
// handles previous State + redux + API call
onChange={this.handleSweetRequest}
disabled={this.state.redSweetClick}
/>
}
label="Sweet"
/>
<FormControlLabel
control={
<Switch
// configuring @material-ui Switch componanet
// value="hidden"
value="RedDry"
color="primary"
id="redDry"
disableRipple
// handles previous State + redux + API call
onChange={(event) => this.handleDryRequest(event)}
disabled={this.state.redDryClick}
/>
}
label="Dry"
/>
<FormControlLabel
control={
<Switch
// configuring @material-ui Switch componanet
value="hidden"
color="primary"
id="redBoth"
disableRipple
// handles previous State + redux + API call
onChange={this.handleBothRequest}
disabled={this.state.redBothClick}
/>
}
label="Both"
/>
<div>
{searchResults}
</div>
</div>
)
}
}
function mapStateToProps(state) {
return {
dryRedBottles: state.redWineReducer
};
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
fetchDryReds: fetchDryReds
}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(Red);
Ниже мой actionCreator;
export function fetchDryReds(redDryState) {
return (dispatch) => {
// debugger;
// dispatch({ type: 'LOADING_DRY_REDS' });
return fetch('http://localhost:3001/wine_bottles', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'},
body: JSON.stringify({dryRedBottles: redDryState})})
.then(response => response.json())
.then(dryRedBottles => {
dispatch({ type: 'FETCH_DRY_REDS', dryRedBottles })});
}
}
Ниже мой редуктор;
export default function redWineReducer (state={}, action) {
switch (action.type) {
case 'FETCH_DRY_REDS':
// debugger;
return action.dryRedBottles
default:
return state;
}
}
Это массив объектов, которые я пытаюсь перебрать;