Я провожу свои первые несколько экспериментов с React, и в этом компоненте я вызываю внешний API, чтобы получить список всех игроков NBA, отфильтровать их по teamId, который был получен как опора компонента, и, наконец, отобразить разметку отфильтрованных игроков. .
Одно из соображений заключается в том, что, поскольку я вызываю API и получаю большой список, я сохраняю его в состоянии компонента, чтобы новые вызовы этого компонента использовали это состояние вместо повторного вызова API. Это не производственный код, и у меня нет API, поэтому я делаю это, потому что получал сообщение «Слишком много запросов», так как я постоянно пытаюсь что-то сделать.
В любом случае, когда я пробую этот код, я получаю уже известное:
Превышена максимальная глубина обновления. Это может произойти, когда компонент многократно вызывает setState внутри componentWillUpdate или componentDidUpdate. React ограничивает количество вложенных обновлений, чтобы предотвратить бесконечные циклы.
Я изучил разметку и не думаю, что делаю какие-либо вызовы методов, которые могут вызвать повторное срабатывание метода рендеринга и так далее, поэтому я не понимаю, почему это происходит.
Спасибо заранее за любую помощь.
Вот рассматриваемый код:
class Players extends Component {
nbaPlayersUrl = "https://someUrl.com";
state = {
players: null,
selectedTeamPlayers: null
};
render() {
if (this.props.teamId === null) return null;
if (this.state.players !== null) {
var selectedTeamPlayers = this.filterPlayersByTeamId(this.state.players);
var markup = this.getMarkup(selectedTeamPlayers);
this.setState({selectedTeamPlayers: markup});
} else {
this.getPlayersList();
}
return (
this.state.selectedTeamPlayers
);
}
getPlayersList() {
let api = new ExternalApi();
let that = this;
api.get(this.nbaPlayersUrl).then(r => {
r.json().then(result => {
let players = result.data.map(p => ({
id: p.id,
firstName: p.first_name,
lastName: p.last_name,
position: p.position,
heightInches: p.height_inches,
heightFeet: p.height_feet,
weightPounds: p.weight_pounds,
teamId: p.team.id
}));
that.setState({players: players});
var selectedTeamPlayers = that.filterPlayersByTeamId(players);
var markup = that.getMarkup(selectedTeamPlayers);
that.setState({selectedTeamPlayers: markup});
});
});
}
filterPlayersByTeamId(players) {
return players.filter(p => {
return p.teamId === this.props.teamId;
});
}
getMarkup(players) {
var result = players.map(p => {
<li key={p.id}>
<div>
<label htmlFor="firstName">First Name</label> <input type="text" name="firstName" value={p.firstName} readOnly></input>
</div>
<div>
<label htmlFor="lastName">Last Name</label> <input type="text" name="lastName" value={p.lastName} readOnly></input>
</div>
<div>
<label htmlFor="position">Position</label> <input type="text" name="position" value={p.position} readOnly></input>
</div>
</li>
});
return (
<ul>
{result}
</ul>
);
}
}
export default Players;
3 ответа
@Sergio Romero - вы НЕ МОЖЕТЕ установить состояние в функции рендеринга, так как это установленное состояние вызовет новый рендер, который снова установит состояние и вызовет новый рендеринг, а также создаст бесконечный цикл. Ваша загрузка данных находится в состоянии рендеринга и настройки, что также создает бесконечные циклы. Вам нужно полностью переписать свой рендер, чтобы он отображал только состояние и свойства (он никогда не должен манипулировать или загружать данные). Я думаю, что вы хотите, это скорее так:
class Players extends Component {
nbaPlayersUrl = "https://someUrl.com";
static propTypes = {
teamId: PropTypes.number
};
static defaultProps = {
teamId: null
};
constructor(props) {
super(props);
this.state = {
players: null
};
}
componentDidMount() {
this.getPlayerList();
}
filterPlayersByTeamId(players, teamId) {
return players.filter(p => {
return p.teamId === teamId;
});
}
getPlayersList = () => {
let api = new ExternalApi();
api.get(this.nbaPlayersUrl).then(r => {
r.json().then(result => {
let players = result.data.map(p => ({
id: p.id,
firstName: p.first_name,
lastName: p.last_name,
position: p.position,
heightInches: p.height_inches,
heightFeet: p.height_feet,
weightPounds: p.weight_pounds,
teamId: p.team.id
}));
this.setState({players});
});
});
};
render() {
if (!this.props.teamId || !this.state.players) return null;
const selectedTeamPlayers = this.filterPlayersByTeamId(this.state.players, this.props.teamId);
return (
<ul>
{
selectedTeamPlayers.map(player => {
<li key={player.id}>
<div>
<label htmlFor="firstName">First Name</label><input type="text" name="firstName" value={player.firstName} readOnly></input>
</div>
<div>
<label htmlFor="lastName">Last Name</label><input type="text" name="lastName" value={player.lastName} readOnly></input>
</div>
<div>
<label htmlFor="position">Position</label><input type="text" name="position" value={player.position} readOnly></input>
</div>
</li>
})
}
</ul>
);
}
}
export default Players;
Если состояние и свойства изменяются, компонент будет повторно визуализирован. в вашей функции render ():
if (this.state.players !== null) {
var selectedTeamPlayers = this.filterPlayersByTeamId(this.state.players);
var markup = this.getMarkup(selectedTeamPlayers);
// this.setState({selectedTeamPlayers:
}
Попробуйте изменить закомментированную строку, каждый раз, когда игроки не обнуляют, состояние компонента обновляется, поэтому функция Render компонента будет запускаться снова.
Поскольку мы не можем установить состояние внутри функции рендеринга, потому что это вызовет побочный эффект, вы не можете вызвать getPlayersList () внутри функции рендеринга.
Решение, упомянутое @Jason Bellomy, - это правильный способ решить эту проблему с помощью вызова getPlayerList внутри componentDidMount, потому что он вызывается сразу после того, как компонент вставлен в дерево, поэтому это место для установки начальных данных для рендеринга страницы.
class Players extends Component {
nbaPlayersUrl = "https://someUrl.com";
state = {
players: null,
selectedTeamPlayers: null,
};
componentDidMount(){
this.getPlayersList();
}
render() {
if (this.props.teamId === null) return null;
if (this.state.players !== null && this.state.selectedTeamPlayers !== null) {
return this.getMarkup(selectedTeamPlayers);
} else {
return (<span> Loading ... </span>);
}
}
getPlayersList() {
let api = new ExternalApi();
let that = this;
api.get(this.nbaPlayersUrl).then(r => {
r.json().then(result => {
let players = result.data.map(p => ({
id: p.id,
firstName: p.first_name,
lastName: p.last_name,
position: p.position,
heightInches: p.height_inches,
heightFeet: p.height_feet,
weightPounds: p.weight_pounds,
teamId: p.team.id
}));
var selectedTeamPlayers = that.filterPlayersByTeamId(players);
that.setState({
players: players,
selectedTeamPlayers: selectedTeamPlayers,
});
});
});
}
filterPlayersByTeamId(players) {
return players.filter(p => {
return p.teamId === this.props.teamId;
});
}
getMarkup(players) {
var result = players.map(p => {
<li key={p.id}>
<div>
<label htmlFor="firstName">First Name</label> <input type="text" name="firstName" value={p.firstName} readOnly></input>
</div>
<div>
<label htmlFor="lastName">Last Name</label> <input type="text" name="lastName" value={p.lastName} readOnly></input>
</div>
<div>
<label htmlFor="position">Position</label> <input type="text" name="position" value={p.position} readOnly></input>
</div>
</li>
});
return (
<ul>
{result}
</ul>
);
}
}
export default Players;
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.