简体   繁体   English

当商店状态改变时,React 组件不会更新

[英]React component not updating when store state has changed

Below is my component class.下面是我的组件类。 The component never seems to execute componentWillUpdate(), even when I can see the state updating by logging before the return in mapStateToProps.该组件似乎永远不会执行 componentWillUpdate(),即使我可以通过在 mapStateToProps 中返回之前记录来查看状态更新。 The state is 100% changing, however the component doesn't refresh.状态 100% 更改,但组件不会刷新。

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { search } from './mapActions'
import L from 'leaflet'


class Map extends Component {
  componentDidMount() {
    L.Icon.Default.imagePath = './images'
    this.map = new L.Map('map', {
      center: new L.LatLng(this.props.lat, this.props.lng),
      zoom: this.props.zoom,
      layers: L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '<a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      })
    })
  }
  componentWillUpdate() {
    console.log('UPDATE MAP')
    L.geoJson(this.props.data).addTo(this.map)
  }
  render() {
    return <div id="map"></div>
  }
}

const mapStateToProps = (state) => {
  return {
    isFetching: state.isFetching,
    data: state.data
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    search: (name) => {
      dispatch(search(name))
    }
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Map)

And here is the map reducer:这是地图减速器:

const initialState = {
  isFetching: false,
  data: {}
}

export const map = (state = initialState, action) => {
  switch(action.type) {
    case 'REQUEST_SEARCH_RESULTS':
      return Object.assign({}, state, {
        isFetching: true
      })
    case 'RECEIVE_SEARCH_RESULTS':
      return Object.assign({}, state, {
        isFetching: false,
        data: action.data
      })
    default:
      return state
  }
}

After some more testing and logging it seems that when it goes to map state to props the state object it uses to map to props contains the correct data, so state.map.data is correct and I can see the return from the fetch.经过一些更多的测试和记录后,似乎当它将状态映射到道具时,它用来映射到道具的状态对象包含正确的数据,所以 state.map.data 是正确的,我可以看到从 fetch 返回。 However when I then log this.props in componentWillUpdate(), the data object is there but empty.但是,当我在 componentWillUpdate() 中记录 this.props 时,数据对象在那里但为空。

I had a similar problem and I found out the answer after read this:我有一个类似的问题,我在阅读后找到了答案:

Data gets set/updated/deleted in the store via the results of handling actions in reducers.数据通过 reducer 中处理操作的结果在 store 中设置/更新/删除。 Reducers receive the current state of a slice of your app, and expect to get new state back. Reducers 接收应用程序切片的当前状态,并期望获得新状态。 One of the most common reasons that your components might not be re-rendering is that you're modifying the existing state in your reducer instead of returning a new copy of state with the necessary changes (check out the Troubleshooting section).您的组件可能不会重新渲染的最常见原因之一是您正在修改减速器中的现有状态,而不是返回带有必要更改的新状态副本(请查看故障排除部分)。 When you mutate the existing state directly, Redux doesn't detect a difference in state and won't notify your components that the store has changed.当您直接改变现有状态时,Redux 不会检测到状态差异,也不会通知您的组件存储已更改。 So I'd definitely check out your reducers and make sure you're not mutating existing state.所以我肯定会检查你的减速器并确保你没有改变现有状态。 Hope that helps!希望有帮助! ( https://github.com/reactjs/redux/issues/585 ) ( https://github.com/reactjs/redux/issues/585 )

When I tried use Object.assign({}, object) as you, it didn't work anyway.当我尝试像你一样使用Object.assign({}, object)时,它无论如何都不起作用。 So was when I found this:当我发现这个时也是如此:

Object.assign only makes shallow copies. Object.assign 只制作浅拷贝。 ( https://scotch.io/bar-talk/copying-objects-in-javascript ) ( https://scotch.io/bar-talk/copying-objects-in-javascript )

Then I understood that I had to do this: JSON.parse(JSON.stringify(object))然后我明白我必须这样做: JSON.parse(JSON.stringify(object))

or just this: {...object}或者只是这个: {...object}

For Arrays: [...theArray]对于数组: [...theArray]

I hope that this will help you我希望这会帮助你

Because you're not changing the reference, so React's shallow compare doesn't detect the update.因为你没有改变引用,所以 React 的浅比较不会检测到更新。

I'm going to use a simple example with blog posts.我将在博客文章中使用一个简单的示例。 In your reducer, you're probably doing something as follows:在您的减速器中,您可能正在执行以下操作:

case FETCH_NEW_POSTS
    let posts = state.posts;
    posts.push(action.payload.posts);
    return {
        ...state, 
        posts
    };

Instead of that, you must do something like the following:取而代之的是,您必须执行以下操作:

case FETCH_NEW_POSTS
    let posts = [...state.posts]; // we're destructuring `state.posts` inside of array, essentially assigning the elements to a new array.
    posts.push(action.payload.posts);
    return {
        ...state, 
        posts
    };

Depending on your use case Object.assign() or lodash's clone/deepclone may be more idiomatic.根据您的用例 Object.assign() 或 lodash 的 clone/deepclone 可能更惯用。

componentWillUpdate receives the incoming props as an argument . componentWillUpdate接收传入的 props作为参数 At this time, this.props is still the old props.这时候this.props还是旧的 props。 Try changing your method like so:尝试像这样改变你的方法:

void componentWillUpdate(nextProps, nextState) {
    L.geoJson(nextProps.data).addTo(this.map);
}

Also, be careful when using the constructor of the component. 另外,使用组件的构造函数时要小心。 That was my problem. 那是我的问题。

eg 例如

class extends Component {
   private elementState: ElementState // BAD idea!!

   constructor(props: any) {
      super(props)
      elementState = stateFromReduxStore // BAD idea!!!
   }

   render() {
      return <SomeElement state={elementState} /> // will not be updated!!!
   }
}

Make sure you are listening to that store in your maps file if you are passing props to your component through maps file.如果您通过地图文件将道具传递给您的组件,请确保您正在收听地图文件中的存储。

export const listenToStores = [CommonStore, store];
@connection(maps.listenToStores, maps.getStateFromStores)

Building on what Marina answered going from建立在玛丽娜回答的基础上

var tempArray = imageArrayState
tempArray.push(5)
setImageArray(tempArray)

to

var tempArray = []
imageArrayState.foreach(value => {tempArray.push(value)})
tempArray.push(5)
setImageArray(tempArray)

made my app refresh让我的应用程序刷新

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM