Reactjs Redux:mapStateToProps 在状态改变时不渲染组件 [英] Reactjs Redux:mapStateToProps not rendering the component on state change

查看:32
本文介绍了Reactjs Redux:mapStateToProps 在状态改变时不渲染组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在同一个组件上有搜索过滤器和排序输入.我正在使用 reselect(selector package) 其中数据数组被过滤和排序.mapStateToProps 正在更新每个搜索过滤器结果上的组件.但 mapStateToProps 不会在对数组进行排序后更新组件.

选择器/index.js

import { createSelector } from 'reselect'const getListOfCategory = (状态) =>状态.产品.产品const getSearchText = (状态) =>state.products.searchTextconst getSortValue = (状态) =>状态.产品.sortValue导出 const getVisibleCategory = createSelector([ getListOfCategory, getSearchText, getSortValue ],(ListOfCategory, searchText, sortValue) =>{if((searchText !== undefined) && (searchText !== null) && (searchText !== "")){返回 ListOfCategory.filter((val) => val.modelname.toLowerCase().includes(searchText.toLowerCase())).sort((a, b) => {如果(sortValue === '喜欢'){返回 b.modellikes - a.modellikes;}如果(排序值 === '视图'){返回 b.modelviews - a.modelviews;}如果(sortValue === '品牌'){返回 a.modelname >b.型号名称?1 : a.modelname <b.型号名称?-1:0;}});}如果(排序值){返回 ListOfCategory.sort((a, b) => {如果(sortValue === '喜欢'){返回 b.modellikes - a.modellikes;}如果(排序值 === '视图'){返回 b.modelviews - a.modelviews;}如果(sortValue === '品牌'){返回 a.modelname >b.型号名称?1 : a.modelname <b.型号名称?-1:0;}});}})

这是我的反应组件.

从'react'导入React;从'react-redux'导入{connect};从../actions/productActions"导入 {getCategoryInfo,search,sortBy};从'../selectors'导入{getVisibleCategory};从 'react-router-dom' 导入 {Link};类 SmartCategory 扩展了 React.Component{构造函数(道具){超级(道具);this.state={搜索过滤器:""}this.searchHandle=this.searchHandle.bind(this);this.sortHandle=this.sortHandle.bind(this);}搜索句柄(e){this.setState({搜索过滤器:e.target.value});this.props.search(e.target.value);}排序句柄(e){this.props.sortBy(e.target.value);}componentDidMount(){this.props.getCategoryInfo(this.props.page,this.props.pageId);}componentWillReceiveProps(nextProps){if(nextProps.page !== this.props.page || nextProps.pageId !== this.props.pageId){this.props.getCategoryInfo(nextProps.page,nextProps.pageId);}}更改文本(){if(this.props.categoryTitle != undefined){let categoryTitle=this.props.categoryTitle.charAt(0).toUpperCase() + this.props.categoryTitle.slice(1);categoryTitle=categoryTitle.split('_').join('');返回类别标题;}}使成为(){const {error,isLoading}=this.propsif(error) return ;if(isLoading) 返回 <div className="spinner"></div>;返回 (<div className="container-fluid mb-4 categoryWrapper"><div className="row mx-0 pt-4"><div className="col-sm-2 col-md-2 col-lg-2 px-2"><div className="input-group mb-3"><div className="input-group-prepend"><span className="input-group-text" id="basic-addon1"><i className="fa fa-search" aria-hidden="true"></i></span>;

<输入类型=文本"类名=表单控件"placeholder="按品牌搜索"onChange={this.searchHandle}值={this.state.searchFilter}/>

<div className="col-sm-2 col-md-2 col-lg-2 px-2"><div className="form-group"><select className="form-control" id="sel1"placeholder="-- 排序方式 -- "onChange={this.sortHandle}><禁用选项>-- 排序方式--</option><option value="brand" >Brand</option><option value="likes">喜欢</option><option value="views">Views</option></选择>

<div className="row mx-0 py-3">{this.props.isLoading ?<div className="spinner"></div>: 空值}{this.props.product &&this.props.product.map((product,i)=><div className="col-sm-3 col-md-3 col-lg-3" key={product.id}><链接到={`/SmartView/${this.props.page}/${product.modelname}`} className="routeDecorator"><div className="边框 mb-2 p-3 四舍五入"><span className="text-grey"><span className="mr-2"><i className="fa fa-thumbs-o-up" aria-hidden="true">{product.modellikes}</i></span><span className="float-right"><i className="fa fa-eye" aria-hidden="true">{product.modelviews} 视图</i></span></span>

</链接>

)}

);}}函数 mapStateToProps(state){const {isLoading,isLoaded,error,categoryTitle,product,searchText,sortValue} = state.products返回 {正在加载,错误,产品:getVisibleCategory(state) ||产品,类别标题}}导出默认连接(mapStateToProps,{getCategoryInfo,search,sortBy})(SmartCategory);

解决方案

MapStateToProps 对每次返回的值进行浅层比较.浅比较将比较对象和数组的引用.排序时,数组按原位排序,因此引用不会改变.请参阅sort.您可以通过返回对数组的新引用来证明这一点:

 return [...ListOfCategory.sort(a,b)//排序代码的其余部分]

I have search filter and sort inputs on the same component.I'm using reselect(selector package) where the data array is filtered and sorted. The mapStateToProps is updating the component on each search filter result.but the mapStateToProps is not updating the component after sorting the array.

selectors/index.js

import { createSelector } from 'reselect'

const getListOfCategory = (state) => state.products.product
const getSearchText = (state) => state.products.searchText
const getSortValue = (state) => state.products.sortValue

export const getVisibleCategory = createSelector(
  [ getListOfCategory, getSearchText, getSortValue ],
  (ListOfCategory, searchText, sortValue) =>{
    if((searchText !== undefined) && (searchText !== null) && (searchText !== "")){
      return ListOfCategory.filter((val) => val.modelname.toLowerCase().includes(searchText.toLowerCase())).sort((a, b) => {
      if (sortValue === 'likes') {
        return b.modellikes - a.modellikes;
      }
      if (sortValue === 'views') {
        return b.modelviews - a.modelviews;
      }
      if (sortValue === 'brand') {
        return a.modelname > b.modelname ? 1 : a.modelname < b.modelname ? -1 : 0;
      }
    });
  }
  if(sortValue){
    return ListOfCategory.sort((a, b) => {
    if (sortValue === 'likes') {
      return b.modellikes - a.modellikes;
    }
    if (sortValue === 'views') {
      return b.modelviews - a.modelviews;
    }
    if (sortValue === 'brand') {
      return a.modelname > b.modelname ? 1 : a.modelname < b.modelname ? -1 : 0;
    }
  });

  }
}
)

Here is my react component.

import React from 'react';
import {connect} from 'react-redux';
import {getCategoryInfo,search,sortBy} from '../actions/productActions';
import {getVisibleCategory} from '../selectors';
import {Link} from 'react-router-dom';

 class SmartCategory extends React.Component{
   constructor(props){
     super(props);
     this.state={
       searchFilter:""
     }
     this.searchHandle=this.searchHandle.bind(this);
     this.sortHandle=this.sortHandle.bind(this);
   }

   searchHandle(e){
     this.setState({
      searchFilter:e.target.value
    });
    this.props.search(e.target.value);
   }

   sortHandle(e){
     this.props.sortBy(e.target.value);
   }

   componentDidMount(){
     this.props.getCategoryInfo(this.props.page,this.props.pageId);
   }

   componentWillReceiveProps(nextProps){
      if(nextProps.page !== this.props.page || nextProps.pageId !== this.props.pageId){
          this.props.getCategoryInfo(nextProps.page,nextProps.pageId);
      }
   }

  changeText(){
    if(this.props.categoryTitle != undefined){
      let categoryTitle=this.props.categoryTitle.charAt(0).toUpperCase() + this.props.categoryTitle.slice(1);
      categoryTitle=categoryTitle.split('_').join(' ');
      return categoryTitle;
    }
  }

render(){
  const {error,isLoading}=this.props
    if(error) return <ResourceNotFound error={error}/>;
    if(isLoading) return <div className="spinner"></div>;
    return (
      <div className="container-fluid mb-4 categoryWrapper">
        <div className="row mx-0 pt-4">
          <div className=" col-sm-2 col-md-2 col-lg-2 px-2">
            <div className="input-group mb-3">
              <div className="input-group-prepend">
                <span className="input-group-text" id="basic-addon1"><i className="fa fa-search" aria-hidden="true"></i></span>
              </div>
              <input type="text"
              className="form-control"
              placeholder="Search by brand"
              onChange={this.searchHandle}
              value={this.state.searchFilter}
               />
            </div>
          </div>
          <div className=" col-sm-2 col-md-2 col-lg-2 px-2">
            <div className="form-group">
              <select className="form-control" id="sel1"
              placeholder="-- Sort By -- "
              onChange={this.sortHandle}
              >
                <option disabled>-- Sort By --</option>
                <option value="brand" >Brand</option>
                <option value="likes">Likes</option>
                <option value="views">Views</option>
              </select>
            </div>
          </div>
        </div>
        <div className="row mx-0 py-3">
          {this.props.isLoading ? <div className="spinner"></div> : null}
            {this.props.product && this.props.product.map((product,i)=>
                <div className="col-sm-3 col-md-3 col-lg-3" key={product.id}>
                  <Link to={`/SmartView/${this.props.page}/${product.modelname}`} className="routeDecorator">
                    <div className="border mb-2 p-3 rounded ">

                        <span className="text-grey">
                        <span className="mr-2">
                        <i className="fa fa-thumbs-o-up" aria-hidden="true"> {product.modellikes}</i>
                        </span>
                        <span className="float-right">
                        <i className="fa fa-eye" aria-hidden="true"> {product.modelviews} views</i>
                        </span>
                        </span>
                    </div>
                  </Link>
                </div>
            )}
        </div>
      </div>
    );
  }
}

function mapStateToProps(state){
  const {isLoading,isLoaded,error,categoryTitle,product,searchText,sortValue} = state.products
    return {
        isLoading,
        error,
        product:getVisibleCategory(state) || product,
        categoryTitle
    }
}

export default connect(mapStateToProps,{getCategoryInfo,search,sortBy})(SmartCategory);

解决方案

MapStateToProps does a shallow compare of the values returned each time. A shallow compare will compare references for objects and arrays. When you sort, the array is sorted in place, so the reference doesn't change. See sort. You could prove it by returning a new reference to the array:

 return [...ListOfCategory.sort(a,b) // rest of sort code ]

这篇关于Reactjs Redux:mapStateToProps 在状态改变时不渲染组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆