Мне кажется, что когда происходит первый в истории рендеринг, this.wikiLink
называется , который называется , а не передается как ссылка .Почему я так думаю?Потому что я вижу круглые скобки там.Тело этого метода содержит вызов this.setState
, что означает, что состояние компонента изменяется во время рендеринга, и это является нарушением жизненного цикла компонента.
Рассмотрим случай:
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
buttonClicked: false,
};
this.handleClickButton = this.handleClickButton.bind(this);
}
handleClickButton() {
this.setState({
buttonClicked: true,
});
}
render() {
return (
<button onClick={this.handleClickButton()}>click me</button>
);
}
}
Есть проблема!Выражение this.handleClickButton()
является вызовом функции.Внутри него есть инструкция по изменению состояния.Когда код пытается это сделать, React отображает предупреждение:
Предупреждение: setState (...): невозможно обновить во время существующего перехода состояния (например, в render
или в конструкторе другого компонента).).Методы рендеринга должны быть чистой функцией реквизита и состояния;побочные эффекты конструктора являются анти-паттернами, но их можно переместить в componentWillMount
.
. Вместо этого мы действительно хотим вызвать функцию this.handleClickButton
при нажатии кнопки.Для этого нам нужно передать ссылку на эту функцию в onClick
реквизит, например:
render() {
return (
<button onClick={this.handleClickButton}>click me</button>
);
}
обратите внимание на отсутствие круглых скобок.
Итак, что вы должны сделатьтогда?
Есть две опции:
Опция 1: анонимная функция внутри onClick
Вместо записи
render() {
return (
// i want to use it something like this
<a href="this.state.TEAM_WIKI" onClick={this.wikiLink(TEAM_NAME)} />
);
}
do
render() {
return (
// i want to use it something like this
<a href="this.state.TEAM_WIKI" onClick={() => this.wikiLink(TEAM_NAME)} />
);
}
Таким образом, ссылка на анонимную функцию, объявленную на месте, передается при каждом вызове render
метода экземпляра компонента.Затем эта функция будет вызываться в какой-то непредсказуемый момент времени, когда пользователь решит щелкнуть, то есть отправить MouseEvent типа «click».
Вариант 2: сделать this.wikiLink (•) returnфункция!
Концепция функции, возвращающей функцию, часто упоминается как частичное применение или, в случаях, подобных этому, чаще всего, замыкание .Таким образом, функция wikiLink
будет вместо этого:
wikiLink(TEAM_NAME) {
// getting TEAM_NAME from a component inside the render method
const wiki = this.state.API_DATA.map(provider => {
if ((provider.team_name = TEAM_NAME && provider.team_wiki !== null)) {
return provider.team_wiki;
}
}).map(link => {
if (link !== undefined) {
return link;
}
});
this.setState({
// TEAM_WIKI is a state { its a string } where i want to store the
//team_wiki at last
TEAM_WIKI: wiki
});
}
выглядеть следующим образом:
wikiLink(TEAM_NAME) {
return () => {
// getting TEAM_NAME from a component inside the render method
const wiki = this.state.API_DATA.map(provider => {
if ((provider.team_name = TEAM_NAME && provider.team_wiki !== null)) {
return provider.team_wiki;
}
}).map(link => {
if (link !== undefined) {
return link;
}
});
this.setState({
// TEAM_WIKI is a state { its a string } where i want to store the
//team_wiki at last
TEAM_WIKI: wiki
});
};
}
Так что при вызове она возвращает новую функцию.Поскольку ожидается, что onClick
prop получит функцию, мы решаем проблему сопоставления типов.Поскольку мы вызываем wikiLink
с некоторым аргументом TEAM_NAME
и этот аргумент применяется каждый раз, когда выполняется эта функция, мы решаем проблему сохранения контекста.Разве это не круто!
Чтобы получить более полное представление об использовании функции, возвращающей функцию, посмотрите этот кодовый ящик , строки с 16 по 23. Надеюсь, это даст некоторыеидея о том, как использовать замыкания в ситуациях, когда вам нужно управлять состоянием компонента React.
Cheers!