Подтвердить что ты не робот

React: почему дочерний компонент не обновляется при изменении prop

Почему в следующем примере псевдокода Child не перерисовывает, когда Container меняет foo.bar?

Container {
  handleEvent() {
    this.props.foo.bar = 123
  },

  render() {
    return <Child bar={this.props.foo.bar} />
}

Child {
  render() {
    return <div>{this.props.bar}</div>
  }
}

Даже если я вызову forceUpdate() после изменения значения в контейнере, Child все еще показывает старое значение.

4b9b3361

Ответ 1

Потому что дети не изменяют, если изменяются реквизиты родителя, но если изменяется его СОСТОЯНИЕ :)

То, что вы показываете, это: https://facebook.github.io/react/tips/communicate-between-components.html

Он будет передавать данные от родителя к потомку через реквизит, но там нет логики рендеринга.

Вам нужно установить какое-то состояние для родителя, а затем переопределить дочерний элемент в состоянии изменения родителя. Это могло бы помочь. https://facebook.github.io/react/tips/expose-component-functions.html

Ответ 2

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

Child {
  render() {
    return <div key={this.props.bar}>{this.props.bar}</div>
  }
}

Ответ 3

В соответствии с компонентом философии React не может изменить свои реквизиты. они должны быть получены от родителя и должны быть неизменными. Только родитель может изменить реквизит своих детей.

приятное объяснение состояние vs реквизит

также, прочитайте эту тему Почему я не могу обновить реквизиты в файле actions.js?

Ответ 4

Вы должны использовать функцию setState. Если нет, штат не сохранит ваши изменения, независимо от того, как вы используете forceUpdate.

Container {
    handleEvent= () => { // use arrow function
        //this.props.foo.bar = 123
        //You should use setState to set value like this:
        this.setState({foo: {bar: 123}});
    };

    render() {
        return <Child bar={this.state.foo.bar} />
    }
    Child {
        render() {
            return <div>{this.props.bar}</div>
        }
    }
}

Ваш код кажется недействительным. Я не могу проверить этот код.

Ответ 5

Используйте функцию setState. Таким образом, вы могли бы сделать

       this.setState({this.state.foo.bar:123}) 

внутри метода события handle.

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

Ответ 6

У меня такая же проблема. Это мое решение, я не уверен, что это хорошая практика, скажите мне, если нет:

state = {
  value: this.props.value
};

componentDidUpdate(prevProps) {
  if(prevProps.value !== this.props.value) {
    this.setState({value: this.props.value});
  }
}

UPD: теперь вы можете сделать то же самое, используя React Hooks: (только если компонент является функцией)

const [value, setValue] = useState(propName);
// This will launch only if propName value has chaged.
useEffect(() => { setValue(propName) }, [propName]);

Ответ 7

Вы, вероятно, должны сделать дочерний элемент функциональным компонентом, если он не поддерживает никакого состояния и просто отображает реквизиты, а затем вызывает их из родительского элемента. Альтернативой этому является то, что вы можете использовать хуки с функциональным компонентом (useState), что приведет к повторной визуализации компонента без состояния.

Также вы не должны изменять пропы, поскольку они неизменны. Поддерживать состояние компонента.

Child = ({bar}) => (bar);