【问题标题】:Last child component overwrites all children最后一个子组件覆盖所有子组件
【发布时间】:2018-12-04 17:59:12
【问题描述】:

我有一个包含 3 个孩子的父反应组件:

<ChildComponent category="foo" />
<ChildComponent category="bar" />
<ChildComponent category="baz" />

子组件根据prop类别值调用api:

http://example.com/listings.json?category=foo

在我的操作中,数据按预期返回。但是,当子组件呈现数据时。最后一个子 baz 也覆盖了它在 foo 和 bar 中的值。

solution to this problem seems to be given here。但我希望这是动态的,并且仅取决于类别道具。这在 Redux 中是不可能的吗?

我的子组件如下所示:

class TweetColumn extends Component {

  componentDidMount() {
    this.props.fetchTweets(this.props.column)
  }

  render() {
    const { tweets, column } = this.props
    if (tweets.length === 0) { return null }
    const tweetItems = tweets[column].map(tweet => (
      <div key={ tweet.id }>
        { tweetItems.name }
      </div>
    )
    return (
      <div className="box-content">
        { tweetItems }
      </div>
    )
  }
}

TweetColumn.propTypes = {
  fetchTweets: PropTypes.func.isRequired,
  tweets: PropTypes.array.isRequired
}

const mapStateToProps = state => ({
  tweets: state.tweets.items
})

export default connect(mapStateToProps, { fetchTweets })( TweetColumn )

减速器

export default function tweetReducer(state = initialState, action) {
  switch (action.type) {
    case FETCH_TWEETS_SUCCESS:
      return {
    ...state,
    [action.data[0].user.screen_name]: action.data
      }
    default:
      return state;
  }
}

export default combineReducers({
    tweets: tweetReducer,
})

行动:

export const fetchTweets = (column) => dispatch => {
  dispatch({ type: FETCH_TWEETS_START })
  const url = `${ TWITTER_API }/statuses/user_timeline.json?count=30&screen_name=${ column }`
  return axios.get(url)
    .then(response => dispatch({
      type: FETCH_TWEETS_SUCCESS,
      data: response.data
    }))
    .then(response => console.log(response.data))
    .catch(e => dispatch({type: FETCH_TWEETS_FAIL}))

}

【问题讨论】:

  • 使用key 道具??
  • @xadm 只需将 key prop 传递给子组件?那没用。
  • keys 应该用于所有相同类型的孩子以帮助区分它们... case .. redux ...您可能正在寻找reselect
  • 你能告诉我们你是如何在你的 redux reducer 中更新 tweets 的吗?我猜你在成功的 api 响应产生的每一个动作上都会覆盖它。
  • @nebuler 更新了问题

标签: reactjs redux react-redux


【解决方案1】:

每次挂载TweetColumn 时,您都会进行一次 api 调用。如果您有多个TweetColumn 组件并且每个都进行api 调用,那么无论哪个最后到达的响应都将设置state.tweets.items 的值。那是因为您每次都发送相同的操作FETCH_TWEETS_SUCCESS(最后一个会覆盖前一个)。为了解决这个问题,假设响应有一个category (foo, bar, baz),我会用以下方式编写reducer:

export default function tweetReducer(state = initialState, action) {
  switch (action.type) {
    case FETCH_TWEETS_SUCCESS:
      return {
          ...state,
          [action.data.category]: action.data
      }
    default:
      return state;
  }
}

然后您可以在 TweetColumn 组件中执行以下操作:

class TweetColumn extends Component {

  componentDidMount() {
    this.props.fetchTweets(this.props.column)
  }

  render() {
    const { column } = this.props;
    const tweetItems = this.props.tweets[column].map(tweet => (
      <div key={ tweet.id }>
        { tweet.name }
      </div>
    )
    return (
      <div className="box-content">
        { tweetItems }
      </div>
    )
  }
}

const mapStateToProps = state => ({
  tweets: state.tweets
})

const mapDispatchToProps = dispatch => ({
  fetchTweets: column => dispatch(fetchTweets(column))
})

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)( TweetColumn )

您必须进行一些验证以确保 tweets[column] 存在,但您明白了。

【讨论】:

  • 响应确实包含类别。然而,数据似乎在呈现tweetItems 后填充,因此this.props.tweets[column] 始终未定义。放置 if (tweets.length === 0) { return null } 会导致它永远不会渲染。
  • @dan-klasson 您能否将fetchTweets 的实现添加到您的问题中?
  • @dan-klasson 我的意思是函数fetchTweets的实现。我猜问题是你没有在fetchTweets 内调度FETCH_TWEETS_SUCCESS 类型的动作,但除非我看到你是如何实现它的,否则我不能100% 确定。
  • 对不起。也添加了动作
  • @dan-klasson 查看我的更新答案,我在末尾添加了mapDispatchToProps
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-17
  • 1970-01-01
  • 2016-06-15
  • 2021-01-15
  • 1970-01-01
  • 2020-07-21
  • 2018-10-05
相关资源
最近更新 更多