Redux状态更新后,ReactJS视图将不会重新渲染

问题描述 投票:0回答:2

istcomponent应该在我添加或更新产品后重新呈现,但不是,我尝试使用immer,但结果是相同的这是我的减速器

import {
  PRODUCT_REMOVED,
  PRODUCT_ADDED,
  PRODUCT_UPDATED,
  ADD_ERROR,
  PRODUCT_LIST,

  LIST_ERROR
} from "../actions/types";

// define default redux state
const DEFAULT_STATE = {
  products: [],
  errorMSG: ""
};
/**
 * return new state with new product subtree based on action type
 * @param  {Object} state  redux old state
 * @param  {Object} action action performed
 * @return {Object}        redux new state
 */
export default (state = DEFAULT_STATE, action) => {
  let new_products;
  let i;
  let j;
  // return new state with new product subtree based on action type
  switch (action.type) {
    case PRODUCT_ADDED:
      new_products = state.products;
      new_products.unshift(action.payload);
      return {
        ...state,
        products: new_products,
        errorMSG: ""
      };

    case PRODUCT_UPDATED:
      new_products = state.products;
      for (i = 0; i < new_products.length; i++)
        if (new_products[i]._id === action.payload._id) {
          new_products[i] = action.payload;
          break;
        }
      return {
        ...state,
        products: new_products,
        errorMSG: ""
      };

    case PRODUCT_REMOVED:
      new_products = state.products;
      for (i = 0; i < new_products.length; i++)
        if (new_products[i]._id === action.payload._id) {
          new_products.splice(i, 1);
          break;
        }
      return {
        ...state,
        products: new_products,
        errorMSG: ""
      };
    case ADD_ERROR:
      return {
        ...state,
        errorMSG: action.payload
      };

    case PRODUCT_LIST:
      return {
        ...state,
        products: action.payload,
        errorMSG: ""
      };

    case LIST_ERROR:
      return {
        ...state,
        errorMSG: action.payload
      };


    default:
      return state;
  }
};

和我的减根剂

import { combineReducers } from "redux";

import authReducer from "./auth";
import subjectReducer from "./subject";
import gradeReducer from "./grade"
import studentReducer from "./student"
import productReducer from "./product"
import teacherReducer from "./teacher"
//create root reducer that will contail other reducers
const rootReducer = combineReducers({
    auth: authReducer,
    subject: subjectReducer,
    grade: gradeReducer,
    student: studentReducer,
    teacher:teacherReducer,
    product:productReducer,

});

export default rootReducer;

和我的组件

import React from 'react';

import { connect } from "react-redux";
import { compose } from "redux";
import { withStyles } from "@material-ui/core/styles";
import PropTypes from "prop-types";
import { validate_name,validate_num } from "../../utils/validators";
import CardActionArea from '@material-ui/core/CardActionArea';
import CardActions from '@material-ui/core/CardActions';
import AddProduct from "./AddProduct";
import Spinner from "../../Spinner";
import TextField from "@material-ui/core/TextField";
import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle";
import Button from '@material-ui/core/Button';

import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
//import AddSubject from './AddSubject'
import * as actions from "../../actions/ProductActions";

import Product  from './Product'

const styles = theme => ({
  root: {
    flexGrow: 1,
  },
  paper: {
    padding: theme.spacing(2),
    textAlign: 'center',
    color: theme.palette.text.secondary,
  }});
class ListProduct extends React.Component {
  constructor(props) {
    super(props);
    this.state =   {
    is_loading: false,
    open:false,
    err: '',
    openDelete:false


  }
}

  /**
   * handle edit after add button is clicked
   * @param  {Object} e  click event
   */
  async handleSubmit(e) {
    e.preventDefault();
      let name_isValid = await validate_name('Name',this.state.name);
      let description_isValid = await validate_name("Description ", this.state.description);
    let price_isValid = await validate_num("Price", this.state.price);
    let stock_isValid = await validate_num("Stock", this.state.stock);


      if ((name_isValid.status && description_isValid.status&& price_isValid.status&& stock_isValid.status) === true) {
        // call product actions creator
        await this.props.editProduct({
          product_id:this.state.id,
          name: this.state.name,
          description: this.state.description,
          price: this.state.price,
          stock: this.state.stock,


        });
        let { errorMSG } = this.props.product;
        if (errorMSG) {
          this.setState({ err: errorMSG });
        } else {
          this.setState({ err: "",open:false });
        }
      } else {
        if (name_isValid.status === false)
          this.setState({ err: name_isValid['text'] });
        else if (description_isValid.status === false)
          this.setState({ err: description_isValid['text'] });
        else if (price_isValid.status === false)
          this.setState({ err: price_isValid['text'] });
       else if (stock_isValid.status === false)
          this.setState({ err: stock_isValid['text'] });

      }
  }

  /**
   * handle change in inputs
   * @param  {String} name input label
   */
  handleChange = name => event => {
    this.setState({
      [name]: event.target.value
    });
  };
  /**
   * close/open dialog box
   */
  toggleDialog = () => {
        this.setState({open:!this.state.open });
  };
  /**
   * handle edit after enter key is pressed
   * @param  {Object} event  key press event
   */
  handleSubmitWithEnterKey = async event => {
    if (event.key === "Enter") {
      event.preventDefault();
      let name_isValid = await validate_name('Name',this.state.name);
      let description_isValid = await validate_name("Description ", this.state.description);
          let price_isValid = await validate_num("Price", this.state.price);
    let stock_isValid = await validate_num("Stock", this.state.stock);


      if ((name_isValid.status && description_isValid.status&& price_isValid.status&& stock_isValid.status) === true) {
        // call product actions creator
        await this.props.editProduct({
                    product_id:this.state.id,

          name: this.state.name,
          description: this.state.description,
          price: this.state.price,
          stock: this.state.stock,


        });
        let { errorMSG ,products} = this.props.product;
        if (errorMSG) {
          this.setState({ err: errorMSG });
        } else {
          this.setState({ err: "",open:false });

        }
      } else {
        if (name_isValid.status === false)
          this.setState({ err: name_isValid['text'] });
        else if (description_isValid.status === false)
          this.setState({ err: description_isValid['text'] });
        else if (price_isValid.status === false)
          this.setState({ err: price_isValid['text'] });
       else if (stock_isValid.status === false)
          this.setState({ err: stock_isValid['text'] });

      }
    }
  };
   /**
   * toggle edit dialog
   * @param  {String} id   product id
   * @param  {String} name product name
  * @param  {Number} price   product price
   * @param  {Number} stock   product stock
   * @param  {String} description product description

   */
  toggleEditDialog = ( id  ,name  ,price  ,stock , description) => e => {
    this.setState({
      open: !this.state.open,
      id: id,
      name: name,
      price: price,
      stock: stock,
      description: description,

      err: ""
    });
  };

  /**
   * handle confirm delete
   * @param  {Object} e button click even
   */
  async handleDelete(e) {
    e.preventDefault();
    // call product actions creator
    await this.props.removeProduct({
      product_id: this.state.id
    });
    let { errorMSG,products } = this.props.product;
    if (errorMSG) {
      this.setState({ err: errorMSG });

    } else this.setState({ openDelete: false, err: "",products:products });
  }
  /**
   * toggle  delete dialog
   * @param  {String}   id         product id
   */
  toggleDeleteDialog = id => e => {
    this.setState({ openDelete: !this.state.openDelete, id: id, err: "" });
  };


    /**
   * buy a product
   * @param  {String}   id         product id
   */
  buy = id => async e => {
    // call product actions creator
        await this.props.buyProduct({
                    product_id:this.state.id});
        let { errorMSG ,products} = this.props.product;
        if (errorMSG) {
          this.setState({ err: errorMSG });
        } else {
          this.setState({ err: ""  });

        }
  };
  /**
   * handle change in inputs
   * @param  {String} name input label
   */
  handleChange = name => event => {
    this.setState({
      [name]: event.target.value });
  };
  async componentDidMount() {
    await this.props.listProduct();
    let { errorMSG ,products} = this.props.product;
    if (errorMSG) {
      this.setState({ err: errorMSG});
    } else this.setState({ err: "" ,products:products });
  }
  render() {



    // if ((typeof this.state.data === 'undefined') || (this.state.is_loading)) {
    //   return (
    //     <div  data-test="ListProductComponent">

    //        <Spinner/>
    //     </div>)
    // }



const{classes}=this.props
    let { products } = this.props.product;
    products=(typeof products==='undefined')?[]:products

  return (
    <div className={classes.root}>
    <AddProduct />
    <br/>
       <Grid container spacing={3}>
       {products
          .map(product => (
        <Grid item xs={12} sm={4} lg={3}>
          <Product currentProduct={product} />
              <CardActions>
         <Button  onClick={this.buy(product._id)}  size="small" color="primary">
          Buy
        </Button>
        <Button onClick={this.toggleEditDialog(product._id,product.name,product.price,product.stock,product.description)}size="small" color="primary">
          Edit
        </Button>
          <Button onClick={this.toggleDeleteDialog(product._id)} size="small" color="secondary">
          Delete
        </Button>

        {product.price +' KSH'}
      </CardActions>
        </Grid>))}
      </Grid>
              <Dialog
          data-test="EditDialog"
          open={this.state.open}
          onClose={this.toggleEditDialog("", "", "", "", "", "", "", "","", "", "", "", "", "", "", "")}
          aria-labelledby="form-dialog-title"
        >
          <DialogTitle id="form-dialog-title">Edit Product</DialogTitle>
          <DialogContent>
             <TextField
                id="name"
                label="Name"
                onChange={this.handleChange("name")}
                margin="normal"
                value={this.state.name}
                autoFocus={true}
                onKeyDown={this.handleSubmitWithEnterKey.bind(this)}
              />
              <br />
                           <TextField
                id="description"
                label="Description"
                onChange={this.handleChange("description")}
                margin="normal"
                value={this.state.description}
                onKeyDown={this.handleSubmitWithEnterKey.bind(this)}
              />
              <br />
            <TextField
                id="price"
                label="Price"
                onChange={this.handleChange("price")}
                margin="normal"
                value={this.state.price}
                onKeyDown={this.handleSubmitWithEnterKey.bind(this)}
              />                      
              <TextField
                id="stock"
                label="Stock"
                onChange={this.handleChange("stock")}
                margin="normal"
                value={this.state.stock}
                onKeyDown={this.handleSubmitWithEnterKey.bind(this)}
              />
            <h1>{this.state.err}</h1>
          </DialogContent>
          <DialogActions>
            <Button
              onClick={this.toggleEditDialog( false, false, false, false, false)}
              color="primary"
            >
              Cancel
            </Button>
            <Button onClick={this.handleSubmit.bind(this)} color="primary">
              Edit
            </Button>
          </DialogActions>
        </Dialog>
        <Dialog
          data-test="DeleteDialog"
          open={this.state.openDelete}
          onClose={this.toggleDeleteDialog("")}
          aria-labelledby="form-dialog-title"
        >
          <DialogTitle id="form-dialog-title">Delete Product</DialogTitle>

          <DialogActions>
            <Button onClick={this.toggleDeleteDialog("")} color="primary">
              Cancel
            </Button>
            <Button color="secondary" onClick={this.handleDelete.bind(this)}>
              Confirm Delete
            </Button>
          </DialogActions>
        </Dialog>
    </div>
  );
  }
}
ListProduct.propTypes = {
  classes: PropTypes.object.isRequired,
  isAuthenticated: PropTypes.bool.isRequired
};
/**
 * map redux this.state to component props
 * @param  {Object } this.state redux this.state
 * @return {object}        component props
 */
function mapStatetoProps(state) {
  return {
    product: state.product,
    rank: state.auth.rank,
    isAuthenticated: state.auth.isAuthenticated
  };
}

export default compose(
  connect(
    mapStatetoProps,
    actions
  ),
  withStyles(styles)
)(ListProduct);

任何人都可以告诉我我做错了什么

reactjs redux
2个回答
0
投票
您就地修改了产品数组,因此对该数组的引用保持不变,并且没有重新渲染的触发器。

尝试类似的东西:

case PRODUCT_ADDED: return { ...state, products: [...state.products, action.payload], errorMSG: "" };


0
投票
[您不应在更改来源时直接将state.products分配给new_products。使用价差运算符

case PRODUCT_ADDED: new_products = ...(state.products); new_products.unshift(action.payload); return { ...state, products: new_products, errorMSG: "" };

© www.soinside.com 2019 - 2024. All rights reserved.