React - состояние обновления на реквизитах изменено - элемент ввода

Я уже прочитал все вопросы о переполнении стека, связанные с этой проблемой, а также это официальный ответный пост и предпочтительные решения.
Больше не рекомендуется использовать componentWillReceiveProps!

Прежде чем пометить этот вопрос как повторяющийся, пожалуйста, поймите мой конкретный вопрос, я не нашел решения для моей конкретной проблемы.

То, что я пытаюсь сделать, очень простое:
у меня есть компонент KInputRange, который получил значение от props и send значение out (обратный вызов) onEnter событие (отправляет значение на сервер только при входе). props.value может случайным образом измениться (поступает через веб-сокет с сервера)

Мой вопрос:
Внутри моих компонентов атрибут <input> value будет получать данные из props или из state?

Если из реквизита: Как я могу обновить значение внутри, когда пользователь вводит данные?

Если из состояния: Как я могу обновить новое значение, если значение props.value было изменено случайным образом с сервера?

Мне действительно нужно обновить свое внутреннее состояние при изменении реквизита, но как это сделать сегодня, если реакция говорит, что это антипаттерн?

Это мой код на данный момент:

class KInputRange extends React.Component<any, any> {
    constructor(props: any) {
        super(props);
    }

    private onKeyDown(e: any): void {
        //If the key is enter call to props.onEnter with the current value

    }

    private onChange(e: any): void {
        //if user change the value- change the internal value
    }

    public render() {
        return (
            <input value={?????} type="text" onChange={(e) => this.onChange(e)} onKeyDown={(e) => this.onKeyDown(e)}/>
        );
    }
}

Использование:

   <KInputRange value={this.state.dataFromTheServer}   onEnter={(val: number) => this.kInputRangeEnterClicked(val)}/>

person cheziHoyzer    schedule 08.04.2019    source источник
comment
Пробовали ли вы использовать getDerivedStateFromProps, вы можете проверить, были ли изменены реквизиты, и если да, вы можете получить обновленное состояние.   -  person Atul    schedule 09.04.2019
comment
Согласно официальному документу, вы будете использовать его только в редких случаях, и мой случай очень тривиален, также статика не годится, мне это нужно, чтобы добавить больше логики.   -  person cheziHoyzer    schedule 15.04.2019


Ответы (4)


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

Что-то вроде этого:

import React, { useState } from 'react';

const KInputRange = (props) => {

    const [value, setValue] = useState(props.value);

    function onKeyDown(e: any): void {
        //If the key is enter call to props.onEnter with the current value
    }

    function onChange(e: any): void {
        setValue(e.target.value);
    }

    return (
            <input value={value} type="text" onChange={(e) => this.onChange(e)} onKeyDown={(e) => this.onKeyDown(e)}/>
    );
}
person neomib    schedule 10.04.2019

Во-первых, как сказал @Atul, вам НЕОБХОДИМО использовать getDerivedStateFromProps. Это все потому, что вам нужно контролировать значение вашего компонента в зависимости от свойств и внутреннего состояния. Предполагая, что вы используете поток, этот код должен помочь:

// @flow
import * as React from "react";

type Properties = {
    remoteValue: string,
    onSubmit: (value: string) => void
};

type State = {
    remoteValueMemo: string,
    internalValue: string
};

class KInputRange extends React.Component<Properties, State> {

    static defaultProps = {
        remoteValue: "",
        onSubmit: () => {}
    };

    state = {
        remoteValueMemo: this.props.remoteValue,
        internalValue: this.props.remoteValue
    };

    static getDerivedStateFromProps(props: Properties, state: State) {
        if (state.remoteValueMemo !== props.remoteValue) {
            return {
                remoteValueMemo: props.remoteValue,
                internalValue: props.remoteValue};
        }
        return null;
    }

    handleValueChange = (event: SyntheticEvent<HTMLInputElement>) => {
        this.setState({internalValue: event.currentTarget.value});
    };

    handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
        if (event.keyCode === 13) {
            this.props.onSubmit(this.state.internalValue);
        }
    };

    render(): React.Node {
        const {internalValue} = this.state;

        return (
            <input value={internalValue} onChange={this.handleValueChange} onKeyDown={this.handleKeyDown}/>
        );
    }
}

export default KInputRange;
person Bender    schedule 16.04.2019
comment
Я знаю это @Bender, и я также пытаюсь его использовать, после того, как я увидел официальный документ, чтобы не использовать его (только в редких случаях), я понимаю, что мой очень тривиальный случай не так тривиален для React, также у меня нет доступ к нему (он статический), и я хочу изменить свой внутренний частный член класса при изменении реквизита, поэтому для меня это не лучшее решение. - person cheziHoyzer; 16.04.2019
comment
Это единственный и идеальный способ реагировать на ваши требования (по крайней мере, на данный момент). Нет ничего особенного в static, он используется только для получения нового состояния в зависимости от изменений свойств отслеживания компонентов. Если вы также хотите реализовать какой-либо побочный эффект при изменении реквизита, вы должны использовать componentDidUpdate - person Bender; 16.04.2019

Аргумент, переданный в useState, не используется для обновления состояния при повторной визуализации.

Вам следует использовать перехватчик useEffect.

import React, { useEffect, useState } from 'react';

const Test = (props) => {

    const [value, setValue] = React.useState({...props.value});

    useEffect(() => {
        setValue(props.value);
    }, [props.value])
  
    //...
}

Аналогичная тема здесь: React.useState не перезагружает состояние из реквизита

person programort    schedule 25.11.2020

Вы можете использовать useEffect хук реакции всякий раз, когда вам нужно что-то сделать при изменении определенных свойств в функциональном компоненте.

useEffect(() => {
    // You can place your logic here to run whenever value changes 
},[value]);

[значение] является зависимостью, поэтому при изменении значения вы используете вызов ловушки.

Надежда, приведенная выше, будет вам полезна.

person Nishith Patel    schedule 16.04.2019
comment
componentWillReceiveProps() считается устаревшим и будет удален в React 17 *, вам следует избегать его использования reactjs.org/ docs / - person Bender; 16.04.2019