Почему в React не обновляется props компонента при изменении хранилища Redux в другом компоненте? — Хабр Q&A

Почему в react не обновляется props компонента при изменении хранилища redux в другом компоненте?

Здравствуйте!

Начал изучать Redux для React. Сразу столкнулся с проблемой общих данных для разных компонентов. Привожу пример кода, который у меня не работает:

Изначально, есть файл index.js, где создано хранилище redux и передано через Provider во все компоненты:

<Provider store={this.state.store}>
    <Header />
    <Body />
    //Здесь ещё другие компоненты
</Provider>

Далее, в компоненте Header я пытаюсь в методе render получить текущие состояние props:

class Header extends React.Component {
    render() {
        console.log(JSON.stringify(this.props.store));
        return ('');
    }
}
export default connect(
    store => ({
        store: store
    })
)(Header);

Но в консоли выводится лишь начальное состояние хранилища, а не то, которое я задал в другом компоненте. Если состояние хранилища обновить из другого компонента – то в другом компоненте можно увидеть обновление хранилища, а в Header всё так же будут старые начальные данные.

Пример обновления хранилища из другого компонента:

class Body extends React.Component {
	componentDidMount() {
		setTimeout(() => {
			updateStore(1);
		});
	}
    render() {
        console.log(JSON.stringify(this.props.store));
        return ('');
    }
}

export default connect(
    store => ({
        store: store
    }),
    dispatch => ({
    	updateStore: (i) => {
    		dispatch({type: 'new', store: i});
    	}
    })
)(Body);

Полагаю, ошибка в чём-то банальном.

Заранее спасибо.

Commonly used lifecycle methods

The methods in this section cover the vast majority of use cases you’ll encounter creating React components. For a visual reference, check out this lifecycle diagram.

Componentdidcatch()

This lifecycle is invoked after an error has been thrown by a descendant component.
It receives two parameters:

  1. error – The error that was thrown.
  2. info – An object with a componentStack key containing information about which component threw the error.

componentDidCatch() is called during the “commit” phase, so side-effects are permitted.
It should be used for things like logging errors:

Production and development builds of React slightly differ in the way componentDidCatch() handles errors.

On development, the errors will bubble up to window, this means that any window.onerror or window.addEventListener(‘error’, callback) will intercept the errors that have been caught by componentDidCatch().

On production, instead, the errors will not bubble up, which means any ancestor error handler will only receive errors not explicitly caught by componentDidCatch().

Note

In the event of an error, you can render a fallback UI with componentDidCatch() by calling setState, but this will be deprecated in a future release.
Use static getDerivedStateFromError() to handle fallback rendering instead.

Componentdidmount()

componentDidMount() is invoked immediately after a component is mounted (inserted into the tree). Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.

This method is a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe in componentWillUnmount().

Componentdidupdate()

componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render.

Use this as an opportunity to operate on the DOM when the component has been updated. This is also a good place to do network requests as long as you compare the current props to previous props (e.g. a network request may not be necessary if the props have not changed).

Componentwillunmount()

componentWillUnmount() is invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, or cleaning up any subscriptions that were created in componentDidMount().

You should not call setState() in componentWillUnmount() because the component will never be re-rendered. Once a component instance is unmounted, it will never be mounted again.

Constructor()

If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.

Читайте также:  Какова разница между SSH ключами для сервера? — Хабр Q&A

Defaultprops

defaultProps can be defined as a property on the component class itself, to set the default props for the class. This is used for undefined props, but not for null props. For example:

If props.color is not provided, it will be set by default to ‘blue’:

If props.color is set to null, it will remain null:

Displayname

The displayName string is used in debugging messages. Usually, you don’t need to set it explicitly because it’s inferred from the name of the function or class that defines the component. You might want to set it explicitly if you want to display a different name for debugging purposes or when you create a higher-order component, see Wrap the Display Name for Easy Debugging for details.

Error boundaries

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

Error handling

These methods are called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component.

Forceupdate()

By default, when your component’s state or props change, your component will re-render. If your render() method depends on some other data, you can tell React that the component needs re-rendering by calling forceUpdate().

Calling forceUpdate() will cause render() to be called on the component, skipping shouldComponentUpdate(). This will trigger the normal lifecycle methods for child components, including the shouldComponentUpdate() method of each child. React will still only update the DOM if the markup changes.

Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render().

Getsnapshotbeforeupdate()

getSnapshotBeforeUpdate() is invoked right before the most recently rendered output is committed to e.g. the DOM. It enables your component to capture some information from the DOM (e.g. scroll position) before it is potentially changed.

This use case is not common, but it may occur in UIs like a chat thread that need to handle scroll position in a special way.

A snapshot value (or null) should be returned.

For example:

In the above examples, it is important to read the scrollHeight property in getSnapshotBeforeUpdate because there may be delays between “render” phase lifecycles (like render) and “commit” phase lifecycles (like getSnapshotBeforeUpdate and componentDidUpdate).

Legacy lifecycle methods

The lifecycle methods below are marked as “legacy”. They still work, but we don’t recommend using them in the new code. You can learn more about migrating away from legacy lifecycle methods in this blog post.

Mounting

These methods are called in the following order when an instance of a component is being created and inserted into the DOM:

Note:

These methods are considered legacy and you should avoid them in new code:

Other apis

Unlike the lifecycle methods above (which React calls for you), the methods below are the methods you can call from your components.

There are just two of them: setState() and forceUpdate().

Props

this.props contains the props that were defined by the caller of this component. See Components and Props for an introduction to props.

In particular, this.props.children is a special prop, typically defined by the child tags in the JSX expression rather than in the tag itself.

Rarely used lifecycle methods

The methods in this section correspond to uncommon use cases. They’re handy once in a while, but most of your components probably don’t need any of them. You can see most of the methods below on this lifecycle diagram if you click the “Show less common lifecycles” checkbox at the top of it.

Redux не обновляет компоненты при обновлении свойств глубокого неизменяемого состояния

сначала две общие мысли:

  • незыблемыми.js is потенциально полезно, да, но вы можете выполнить ту же неизменяемую обработку данных без ее использования. Существует ряд библиотек, которые могут облегчить чтение неизменяемых обновлений данных, но по-прежнему работают с обычными объектами и массивами. У меня многие из них перечислены на Неизменяемые Данные страница в моем репозитории библиотек, связанных с Redux.
  • если компонент React не по-видимому, обновление, это почти всегда потому, что редуктор фактически мутирует данные. В FAQ Redux есть ответ на эту тему, вhttp://redux.js.org/docs/FAQ.html#react-not-rerendering.
Читайте также:  Доставка токена в Россию поставки из КИТАЙ, ИРЛАНДИЯ. Код ТН ВЭД токен.

Теперь, учитывая, что вы are использовать immutable.js, я признаю, что мутация данных кажется немного маловероятной. Вот и все… the file[prop] = fileProps[prop] линия в вашем редукторе кажется ужасно любопытной. Что именно вы собираетесь там делать? Я бы получше посмотри на эту часть.

вообще-то, теперь, когда я смотрю на это… Я почти на 100% уверен, что вы мутируете данные. Ваш обратный вызов updater в state.updateIn(['files', index]) возвращает тот же объект файл, который вы получили в качестве параметра. За неизменное.JS docs at https://facebook.github.io/immutable-js/docs/#/Map:

Если функция updater возвращает то же значение, с которым она была вызвана, то никаких изменений не произойдет. Это по-прежнему верно, если notSetValue предоставлена.

Да. Вы возвращаете то же значение, которое вам было дано, ваши прямые мутации к нему появляются в DevTools, потому что этот объект все еще висит вокруг, но так как вы вернули тот же объект неизменяемым.js фактически не возвращает никаких измененных объектов дальше по иерархии. Таким образом, когда Redux выполняет проверку объекта верхнего уровня, он видит, что ничего не изменилось, не уведомляет подписчиков, и поэтому ваш компонент mapStateToProps никогда работает.

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

(довольно запоздалый ответ, но я только что видел вопрос, и он, кажется, все еще открыт. Надеюсь, ты его уже починил…)

Shouldcomponentupdate()

Use shouldComponentUpdate() to let React know if a component’s output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.

shouldComponentUpdate() is invoked before rendering when new props or state are being received. Defaults to true. This method is not called for the initial render or when forceUpdate() is used.

This method only exists as a performance optimization. Do not rely on it to “prevent” a rendering, as this can lead to bugs. Consider using the built-in PureComponent instead of writing shouldComponentUpdate() by hand. PureComponent performs a shallow comparison of props and state, and reduces the chance that you’ll skip a necessary update.

If you are confident you want to write it by hand, you may compare this.props with nextProps and this.state with nextState and return false to tell React the update can be skipped.

We do not recommend doing deep equality checks or using JSON.stringify() in shouldComponentUpdate(). It is very inefficient and will harm performance.

Currently, if shouldComponentUpdate() returns false, then UNSAFE_componentWillUpdate(), render(), and componentDidUpdate() will not be invoked.

Static getderivedstatefromerror()

This lifecycle is invoked after an error has been thrown by a descendant component.
It receives the error that was thrown as a parameter and should return a value to update state.

Note

getDerivedStateFromError() is called during the “render” phase, so side-effects are not permitted.
For those use cases, use componentDidCatch() instead.

The component lifecycle

Each component has several “lifecycle methods” that you can override to run code at particular times in the process. You can use this lifecycle diagram as a cheat sheet. In the list below, commonly used lifecycle methods are marked as bold. The rest of them exist for relatively rare use cases.

Unmounting

This method is called when a component is being removed from the DOM:

Unsafe_componentwillmount()

Note

This lifecycle was previously named componentWillMount. That name will continue to work until version 17. Use the rename-unsafe-lifecycles codemod to automatically update your components.

UNSAFE_componentWillMount() is invoked just before mounting occurs. It is called before render(), therefore calling setState() synchronously in this method will not trigger an extra rendering. Generally, we recommend using the constructor() instead for initializing state.

Avoid introducing any side-effects or subscriptions in this method. For those use cases, use componentDidMount() instead.

Читайте также:  Что такое криптопро для iOS и какие компоненты для него требуются

This is the only lifecycle method called on server rendering.

Unsafe_componentwillreceiveprops()

Note

This lifecycle was previously named componentWillReceiveProps. That name will continue to work until version 17. Use the rename-unsafe-lifecycles codemod to automatically update your components.

Note:

Using this lifecycle method often leads to bugs and inconsistencies

For other use cases, follow the recommendations in this blog post about derived state.

UNSAFE_componentWillReceiveProps() is invoked before a mounted component receives new props. If you need to update the state in response to prop changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions using this.setState() in this method.

Note that if a parent component causes your component to re-render, this method will be called even if props have not changed. Make sure to compare the current and next values if you only want to handle changes.

React doesn’t call UNSAFE_componentWillReceiveProps() with initial props during mounting. It only calls this method if some of component’s props may update. Calling this.setState() generally doesn’t trigger UNSAFE_componentWillReceiveProps().

Unsafe_componentwillupdate()

Note

This lifecycle was previously named componentWillUpdate. That name will continue to work until version 17. Use the rename-unsafe-lifecycles codemod to automatically update your components.

UNSAFE_componentWillUpdate() is invoked just before rendering when new props or state are being received. Use this as an opportunity to perform preparation before an update occurs. This method is not called for the initial render.

Note that you cannot call this.setState() here; nor should you do anything else (e.g. dispatch a Redux action) that would trigger an update to a React component before UNSAFE_componentWillUpdate() returns.

Typically, this method can be replaced by componentDidUpdate(). If you were reading from the DOM in this method (e.g. to save a scroll position), you can move that logic to getSnapshotBeforeUpdate().

Note

UNSAFE_componentWillUpdate() will not be invoked if shouldComponentUpdate() returns false.

Updating

An update can be caused by changes to props or state. These methods are called in the following order when a component is being re-rendered:

Note:

These methods are considered legacy and you should avoid them in new code:

Компонент react не обновляется при изменении состояния хранилища – javascript |

Привет, я довольно новичок для реакции-редукта.
когда я пытаюсь изменить состояние хранилища, метод render не будет вызван.
Поток для значения, указанного ниже:

1) Изначально, когда я загружаю страницу, я извлекал результирующий набор из API и сохранял состояние следующим образом:

store.views = {
  a: 10,b: 20, c: 30
  d: {
    e: [{
      f: 'temp',
      g: 'temp'
    }, {
      f: 'temp1',
      g: 'temp1'
    }],
    page: 1,
    page_count: 3,
    total_count: 25,
    has_next: true
  }
}

2) Ищите ключевое слово ‘abc’, вызывая API, который обновляет состояние магазинов, которое только обновляет ключ ‘d’ в предыдущем состоянии следующим образом:

store.views = {
  a: 10, b: 20, c: 30
  d: {
    e: [{
      f: 'temp2',
      g: 'temp2'
    }, {
      f: 'temp3',
      g: 'temp3'
    }],
    page: 1,
    page_count: 2,
    total_count: 12,
    has_next: true
  }
}

Вызывается метод

render() и перезагружается страница.

3) Ищите другое ключевое слово ‘def’, вызывая тот же API, что и выше, который обновляет состояние магазинов, которое только обновляет ключ ‘d’ в предыдущем состоянии следующим образом:

store.views = {
  a: 10, b: 20, c: 30
  d: {
    e: [{
      f: 'temp4',
      g: 'temp4'
    }, {
      f: 'temp5',
      g: 'temp5'
    }],
    page: 1,
    page_count: 1,
    total_count: 8,
    has_next: true
  }
}

метод render() не вызывается и не получает соответствующий набор результатов на странице.

Render()

The render() method is the only required method in a class component.

When called, it should examine this.props and this.state and return one of the following types:

The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it’s invoked, and it does not directly interact with the browser.

If you need to interact with the browser, perform your work in componentDidMount() or the other lifecycle methods instead. Keeping render() pure makes components easier to think about.

Note

render() will not be invoked if shouldComponentUpdate() returns false.

Оцените статью
ЭЦП Эксперт
Добавить комментарий