Кажется, основное реакт-кунфу — в умении проводить границы между компонентами. Тогда переделывать становится гораздо проще.
Первый слой разделения: это контейнеры и презентационные компоненты (Дэн Абрамов про это написал достаточно подробно). Контейнеры готовят данные, а презентационные компоненты их отображают. С помощью разных контейнеров мы подгружаем/готовим разные наборы данных, а с помощью одного презентационного — отображаем.
Второй слой: все блоки, которые собираются итератором.
Плохо:
render() {
const list = this.props.people.map(person => (
<li key={person.id}>
<Link to={`/person/${person.id}`}>{person.name}</Link>
</li>
);
return (
<ul>{list}</ul>
)
}
Хорошо:
render(){
const list = this.props.people.map(person => <PersonLi person={person} key={person.id} />)
return (
<ul>{list}</ul>
)
}
и PersonLi
уже отображает <li>
с собственным скоупом. Когда понадобится добавить в такой PersonLi
какую-то логику (а понадобится обязательно), внутри скоупа с объектом работать будет во сто крат проще.
Третий слой: выделять компонент, если блоки явно типовой и будет использоваться в других местах приложения. Например, ссылка на человека.
Плохо:
class PersonLi extens React.Component {
render() {
const person = this.props.person;
return (<li><Link to={`/person/${person.id}`}>{person.name}</Link></li>);
}
}
Хорошо:
class PersonLi extens React.Component {
render() {
return (<li><PersonLink person={this.props.person} /></li>);
}
}
class PersonLink extens React.Component {
render() {
const person = this.props.person;
return (<Link to={`/person/${person.id}`}>{person.name}</Link>);
}
}
Четвертый: совсем уж атомные блоки, из которых собирается интерфейс, и которые отвязаны от логики приложения: инпуты, например. Такой атомный контролируемый инпут отображает переданное ему значение и возвращает в компонент с формой введенное пользователем значение. Тут же обработка шорткатов, например.
export default class Checkbox extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
}
onChange(event){
this.props.onChange(event.target.name, event.target.checked);
}
render() {
return (
<label>
<input
type="checkbox"
name={this.props.name}
checked={this.props.checked}
onChange={this.onChange}/> {this.props.label}
</label>
)
}
}
И вызов такого компонента в какой-нибудь форме:
class Post extends React.Component {
constructor(props){
super(props);
this.state = {
subscribe: false
};
this.updateField = this.updateField.bind(this);
}
updateField(name, value){
this.setState({name: value});
}
render(){
return (
<div className="form">
...
<Checkbox
label="Subscribe to updates"
name="subscribe"
checked={this.state.subscribe}
onChange={this.updateField} />
...
</div>
)
}
}
Наверняка есть готовые npm-пакеты с такими блоками :)