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

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

  render() {
    return 
}

Child {
  render() {
    return 
{this.props.bar}
} }

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

Tuomas Toivonen

Ответов: 17

Ответы (17)

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

приятное объяснение состояние и свойства

также, прочтите эту ветку Почему я не могу обновить props в react.js?

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

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]);

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

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

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

Подтверждено, добавление Ключа работает. Я просмотрел документацию, чтобы попытаться понять, почему.

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

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

https://reactjs.org/docs/reconciliation.html#recursing- на детей

В моем случае было несколько свойств объекта props и необходимость повторно визуализировать дочерний элемент при изменении любого из них. Предложенные выше решения работали, но добавление ключа к каждому из них стало утомительным и грязным (представьте, что у вас есть 15 ...). Если кто-то сталкивается с этим - вам может быть полезно преобразовать объект props в строку:


Таким образом, каждое изменение каждого из свойств в props запускает повторный рендеринг дочернего компонента.

Надеюсь, это кому-то помогло.

When create React components from functions and useState.

const [drawerState, setDrawerState] = useState(false);

const toggleDrawer = () => {
      // attempting to trigger re-render
      setDrawerState(!drawerState);
};

Это не работает

         

Это работает (ключ добавления)

         

В моем случае я обновлял состояние загрузка, которое было передано компоненту. Внутри кнопки props.loading проходил, как ожидалось (переключение с false на true), но троичный элемент, который показал счетчик, не обновлялся.

Я попытался добавить ключ, добавив состояние, которое обновлялось с помощью useEffect () и т. Д., Но ни один из других ответов не помог.

То, что сработало для меня, изменило это:

setLoading(true);
handleOtherCPUHeavyCode();

На это:

setLoading(true);
setTimeout(() => { handleOtherCPUHeavyCode() }, 1)

I assume it's because the process in handleOtherCPUHeavyCode is pretty heavy and intensive so the app freezes for a second or so. Adding the 1ms timeout allows the loading boolean to update and then the heavy code function can do it's work.

Соблюдать неизменяемость

Quite an old question but it's an evergreen problem and it doesn't get better if there are only wrong answers and workarounds. The reason why the child object is not updating is not a missing key or a missing state, the reason is that you don't obey the principle of immutability.

Это цель - сделать приложения более быстрыми, отзывчивыми, простыми в обслуживании и т. Д., Но вы должны следовать некоторым принципам. Узлы React перерисовываются, только если это необходимо, т.е. если они обновились. Как React знает, обновился ли компонент? Потому что его состояние изменилось. Не путайте это с ловушкой setState. Состояние - это концепция, и у каждого компонента есть свое состояние. Состояние - это внешний вид или поведение компонента в данный момент времени. Если у вас есть статический компонент, у вас все время есть только одно состояние, и вам не нужно о нем заботиться. Если компонент должен каким-то образом измениться, его состояние меняется.

Теперь реакция очень наглядна. Состояние компонента может быть получено из некоторой изменяющейся информации, и эта информация может храниться вне компонента или внутри. Если информация хранится внутри, то это некоторая информация, которую компонент должен отслеживать сам, и мы обычно используем хуки, такие как setState, для управления этой информацией. Если эта информация хранится вне нашего компонента, то она хранится внутри другого компонента, и нужно отслеживать ее, свое состояние. Теперь другой компонент может передать нам свое состояние через реквизиты.

Это означает реагирование на повторную визуализацию при изменении нашего собственного управляемого состояния или при изменении информации, поступающей через реквизиты. Это естественное поведение, и вам не нужно передавать данные реквизита в ваше собственное состояние. Теперь наступает очень важный момент: как реагировать на изменение информации? Легко: это делает сравнение! Всякий раз, когда вы устанавливаете какое-либо состояние или даете реагировать некоторую информацию, которую он должен учитывать, он сравнивает вновь предоставленную информацию с фактически сохраненной информацией, и если они не совпадают, response будет повторно отображать все зависимости этой информации. Не то же самое в этом аспекте означает оператор javascript ===. Может быть, вы уже поняли суть. Посмотрим на это:

пусть a = 42;
пусть b = a;
console.log ('это то же самое, что и b?', a === b); // a и b одинаковы, верно? -> верно

а + = 5; // теперь давайте изменим
console.log ('это то же самое, что и b?', a === b); // -> ложь

Мы создаем экземпляр значения, затем создаем другой экземпляр, присваиваем значение первого экземпляра второму экземпляру, а затем изменяем первый экземпляр. Теперь посмотрим на такой же поток с объектами:

пусть a = {число: 42};
пусть b = a;
console.log ('это то же самое, что и b?', a === b); // a и b одинаковы, верно? -> верно
a.num + = 5; // теперь давайте изменим
console.log ('это то же самое, что и b?', a === b); // -> истина

this.props.foo.bar = 123

фактически обновляет значение в памяти, на которое указывает "this". React просто не может распознать такие изменения, сравнивая ссылки на объекты. Вы можете изменить содержимое вашего объекта тысячу раз, и ссылка всегда останется прежней, и реакция не будет выполнять повторную визуализацию зависимых компонентов. Вот почему вы должны рассматривать все переменные в реакции как неизменяемые. Чтобы сделать заметное изменение, вам понадобится другая ссылка, и вы получите ее только с новым объектом. Поэтому вместо того, чтобы изменять свой объект, вы должны скопировать его на новый, а затем вы можете изменить некоторые значения в нем, прежде чем передать его для реакции. Смотреть:

пусть a = {число: 42};
console.log ('похоже на', а);
пусть b = {... a};
console.log ('b выглядит как', b);
console.log ('это то же самое, что и b?', a === b); // -> ложь

Если вы соблюдаете неизменность, все дочерние узлы обновляются новыми данными реквизита.

Я столкнулся с той же проблемой. У меня был компонент Tooltip, который получал showTooltip prop, который я обновлял для компонента Parent на основе условия if, это было обновление в компоненте Parent, но компонент Tooltip не отображался.

const Parent = () => {
   let showTooltip = false;
   if(....){ showTooltip = true; }
   return(
      
   )
}

Я сделал ошибку, объявив showTooltip как let.

Я понял, что делаю не так. Я нарушал принципы работы рендеринга. Замена хуков сработала.

const [showTooltip, setShowTooltip] =  React.useState(false);

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

Child {
  render() {
    return 
{this.props.bar}
} }
export default function DataTable({ col, row }) {
  const [datatable, setDatatable] = React.useState({});
  useEffect(() => {
    setDatatable({
      columns: col,
      rows: row,
    });
  /// do any thing else 
  }, [row]);

  return (
    
  );
}

в этом примере используется useEffect для изменения состояния при изменении props.

определить измененные свойства в mapStateToProps метода подключения дочернего компонента.

function mapStateToProps(state) {
  return {
    chanelList: state.messaging.chanelList,
  };
}

export default connect(mapStateToProps)(ChannelItem);

В моем случае канал channelList обновлен, поэтому я добавил chanelList в mapStateToProps

установочный пакет npm установить response-native-uuid или пряжа добавить react-native-uuid

import ...
import uuid from 'react-native-uuid';

используйте этот метод для uuid для ребенка, чтобы решить проблему повторного рендеринга uuid.v4 ();

Вам следует использовать функцию 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 {
        render() {
            return 
{this.props.bar}
} } }

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

Вы можете использовать componentWillReceiveProps:

componentWillReceiveProps({bar}) {
    this.setState({...this.state, bar})
}

Кредит Джошу Лунсфорду

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

Вы показываете следующее: https://facebook.github.io/react/tips/communicate-between-components.html

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

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

Вы должны были использовать динамический компонент.

В этом фрагменте кода мы визуализируем дочерний компонент несколько раз, а также передаем ключ.

  • Если мы динамически визуализируем компонент несколько раз, React не будет визуализировать этот компонент, пока его ключ не будет изменен.

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

class Parent расширяет Component {
    state = {
        проверено: правда
    }
    оказывать() {
        возвращение (
            
{ [1, 2, 3] .map ( n =>
) }
); } }

2022 WebDevInsider