Хочу дополнить ответ
juicyigor т.к. он содержит одну критическую (для производительности) ошибку:
<First
city={data.city}
handleClick={this.handleClick(data.city)}
/>
handleClick = city => () => {
this.setState({
selectedCity: city,
});
};
Суть в том, что мы при каждом рендере создаем
новый коллбэк и передаем его как prop компоненту First. Во-первых: даже без реакта у вас могут возникнуть проблемы со сборщиком мусора, если вы достаточно часто делаете ререндер. Во-вторых: хорошей практикой для компонентов-представлений (глупых компонентов - dump components) является использование так называемого pure render (путем наследования класса компонента от React.PureComponent). Это дает нам возможность ререндерить (обновлять) компонент только в том случае, если props или state изменились. У Вас в компоненте First state не используется, значит, рендер компонента будет зависеть только от props, но при этом - при каждом рендере родительского компонента вы передаете в First новый экземпляр handleClick. Значит - компонент First будет каждый раз рендерится, даже если по сути - данные не поменялись. Это плохо и
является антипаттерном. Предлагаю вот такой вариант:
class First extends React.PureComponent {
handleClick = () => {
const { onClick, city } = this.props
return onClick(city)
}
render() {
const { onClick, city } = this.props
return (
<div className="first">
<button onClick={onClick && this.handleClick}>
click
</button>
<p>{city}</p>
</div>
)
}
}
В компонент First я добавил метод handleClick, который вызывает коллбэк onClick (который передан через props) и передает туда city. Таким образом мы избавились от пересоздания коллбэка в рендере родительского компонента. Также обратите внимание на определение этого метода:
handleClick = () => {
Такая запись подразумевает в себе автобиндинг: т.е. this у вас будет ссылаться именно на ваш элемент.
И небольшое замечание по названиям: handleSomething - это функция, которую вы передаете в свойство с названием onSomething. Пример:
<input onBlur={handleBlur} />
И исходя из предложенных изменений код родительского компонента будет выглядеть так:
class TestComponent extends React.PureComponent{
constructor() {
super();
this.state = {
selectedCity: false,
};
}
handleClick = city => {
this.setState({
selectedCity: city,
});
};
render() {
return (
<div>
{locations.map((data, i) =>
<First
city={data.city}
onClick={this.handleClick}
/>
)}
<Second city={this.state.selectedCity} />
</div>
);
}
}
PS саму логику я не трогал, просто хотел обратить Ваше внимание на ошибки.