Reactjs Redux:mapStateToProps 状态改变时不渲染组件
Reactjs Redux:mapStateToProps not rendering the component on state change
我使用 reselect(selector package) 在相同的 component.I 上对输入进行搜索筛选和排序,其中对数据数组进行筛选和排序。 mapStateToProps 正在更新每个搜索过滤器上的组件 result.but mapStateToProps 不会在对数组排序后更新组件。
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;
}
});
}
}
)
这是我的反应组件。
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
对每次返回的值进行浅比较。浅比较将比较对象和数组的引用。排序时,数组就地排序,因此引用不会改变。参见 sort。您可以通过返回对数组的新引用来证明这一点:
return [...ListOfCategory.sort(a,b) // rest of sort code ]
我使用 reselect(selector package) 在相同的 component.I 上对输入进行搜索筛选和排序,其中对数据数组进行筛选和排序。 mapStateToProps 正在更新每个搜索过滤器上的组件 result.but mapStateToProps 不会在对数组排序后更新组件。
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;
}
});
}
}
)
这是我的反应组件。
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
对每次返回的值进行浅比较。浅比较将比较对象和数组的引用。排序时,数组就地排序,因此引用不会改变。参见 sort。您可以通过返回对数组的新引用来证明这一点:
return [...ListOfCategory.sort(a,b) // rest of sort code ]