Управление состоянием Faster React для сложных компонентов - PullRequest
0 голосов
/ 18 ноября 2018

Недавно я попытался использовать библиотеки управления состоянием Redux и MobX для React, однако, если вы реализуете более сложные страницы с большим количеством привязок (например, 1000), процесс рендеринга всего VDOM будет немного медленным за разовое изменение имущества государства. Поэтому я попытался реализовать библиотеку, которая бы повторно отображала только те компоненты, которые прослушивают используемое связывание.

В ViewModel вы можете определить наблюдаемые объекты, массивы и действия. Чтобы изменить любое значение, вы можете использовать функцию this.set (похожую на действие redux), которая установит значение наблюдаемой, но компоненты, которые прослушивают эту привязку, будут повторно отображаться позже при вызове this.applyChanges.

export class ArrayViewModel extends ViewModel {
todo: Observable<string> = new Observable("");
todos: ObservableArray<string>
    = new ObservableArray(
        [
            new Observable("milk"),
            new Observable("carrot")
        ]
    );

addTodo = () => {
    this.set(this.todos, [ ...this.todos.get(), new Observable(this.todo.get())]);
    this.set(this.todo, "");
    this.applyChanges();
}

}

Вам потребуется расширить тип компонента и присоединить хранилище (аналогично приставке) с помощью вашей ViewModel (состояние). Для печати любого значения вы можете использовать функцию this.bind, которая будет регистрировать компонент для обновления свойства.

export class ArrayComponent extends Component<ArrayViewModel, ArrayComponentProps, {}> {
constructor(props: ArrayComponentProps) {
    super(props);
}

componentDidMount() {
}

render() {
    return (
        <div>
            <p>
                <Textbox store={this.store} text={this.vm.todo} />
                <button onClick={this.vm.addTodo}>
                    Add Todo
                </button>
            </p>
            <ul>
            {this.bind(this.vm.todos).map(todo => {
                return ( 
                    <li key={todo.id}>
                        <Literal store={this.store} text={todo} />
                    </li>
                );
            })}
            </ul>
            <ul>
            {this.bind(this.vm.todos).map(todo => {
                return ( 
                    <li key={todo.id}>
                        <Textbox store={this.store} text={todo} />
                    </li>
                );
            })}
            </ul>
        </div>
    );
}
}

В компоненте действие set для store может быть легко вызвано при изменении (повторно отображает только текущий компонент) и применено к размытию (повторно отобразятся все компоненты, использующие одну и ту же привязку);

export class Textbox<TProps extends TextboxProps, TState> 
extends Component<ViewModel, TProps, TState> {

constructor(props: TProps & ComponentProps) {
    super(props);

    this.handleChange = this.handleChange.bind(this);
}

handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    this.change(this.props.text, e.target.value);

    if (this.props.onChange) {
        this.props.onChange(e);
    }
}

render() {
    return (
        <input 
            type="text" 
            value={this.bind(this.props.text)}
            onChange={this.handleChange}
            onBlur={this.applyChanges}
        />
    );
}
}

Это не будет быстрее с добавлением, удалением или сортировкой массива, но будет намного быстрее отображать изменения любых значений элементов массива.

enter image description here

Я понимаю, что все можно сделать проще с помощью декораторов (пока не обладайте этим навыком), но я хотел бы спросить, считаете ли вы, что этот подход может повлиять на производительность сложных компонентов, написанных в React. Я довольно новичок в React и могу что-то упустить, поэтому, пожалуйста, дайте мне знать ваше мнение.

1 Ответ

0 голосов
/ 23 ноября 2018

Не изобретай велосипед.

Более сложные варианты использования требуют более глубокого знания того, как реагирует внутренняя работа. Две вещи являются наиболее важными : избегая render и делая результат рендеринга «стабильным» / чистым (тот же результат для тех же параметров) - избегая реальных обновлений DOM в результате сверки (различие VDOM / real DOM).

Вы должны начать с самого начала - нормальное состояние реакции и стандартные оптимизации (документы): shouldComponentUpdate, PureComponent и т. Д.

Вы можете использовать this.props.onChange непосредственно в render (используйте propTypes, чтобы сделать это обязательным). Привязка к render снижает производительность - каждый render вызов создает новую ссылку и вызывает реальное обновление DOM.

...