Управление состоянием Faster React для сложных компонентов

Недавно я попытался использовать библиотеки управления состоянием 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();
}

}

Вам нужно будет расширить тип Component и прикрепить хранилище (аналогично redux) с вашей 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 в хранилище можно легко вызвать при изменении (повторно отображает только текущий компонент) и применить к размытию (повторно отобразит все компоненты, использующие ту же привязку);

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}
        />
    );
}
}

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

введите здесь описание изображения

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


person bojo    schedule 18.11.2018    source источник


Ответы (2)


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

Более сложные варианты использования требуют более глубоких знаний о том, как реагировать на внутренние процессы. Наиболее важны две вещи: избегать render и делать результат рендеринга "стабильным" / чистым (тот же результат для тех же свойств) - избегать реальных обновлений DOM < / strong> в результате согласования (различие VDOM / реального DOM).

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

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

person xadm    schedule 23.11.2018

Я думаю, что @xadm покрывает большую часть этого. Еще несколько дополнений к тому же.

Когда дело доходит до сложных проблем, на которые стоит обратить внимание, очень важны концепции структуры, состояния и производительности. React предоставляет концепции, которые помогут вам улучшить производительность вашего приложения.

Для разделения состояния между компонентами требуется подход подъема состояния. Здесь вы чувствуете потребность в лучшей структуре для управления межкомпонентными состояниями. Хотя такой подход - неплохая идея, вам нужно знать концепции производительности React, прежде чем вы это сделаете. React.PureComponent в приведенном выше случае.

Я уже довольно давно использую Rootz JS в довольно сложных ситуациях. Поскольку он довольно хорошо справляется со сложными изменениями состояния. Это также помогает мне структурировать мое приложение.

Существует образец Todo App, созданный с помощью Rootz JS. На случай, если вы захотите взглянуть.

Вот как выглядит исходный код.

Мне нравится Концепция контрактов, которая может вас заинтересовать.

person ScriptFreak    schedule 11.01.2021