状态更改后,组件不会重新渲染

时间:2019-02-05 10:01:33

标签: reactjs redux

我有一个包含两个按钮组(功能和目标)的界面。当我单击一个按钮时,我希望它从一个团队转到另一个团队。我正在用react和redux实现它。我唯一的问题是,当状态更新并且我成功登录控制台日志时,除非我使用forceUpdate(),否则组件不会。我不明白的是,由于状态更新成功,组件不应该自动重新渲染吗?

Some.js

  import Utils.DBConnection;
    import Utils.IST;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.PrintWriter;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.SQLIntegrityConstraintViolationException;
    import java.sql.Statement;
    import java.util.Properties;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.naming.NamingException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    public class Category extends HttpServlet {

        Connection connection = null;
        Statement statement = null;
        IST ist;
        PrintWriter out;

        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");
            out = response.getWriter();
        }

        public void connectToServer() throws SQLException, NamingException {
            connection = DBConnection.getDataSource().getConnection();
            statement = connection.createStatement();
            ist = new IST();
        }

        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
            try {
                connectToServer();
                switch (request.getParameter("mode")) {
                    case "checkAvailability": {
                        String category_name = request.getParameter("category_name");
                        String sql = "Select category_name from course_category where category_name='" + category_name + "'";
                        ResultSet resultset_val = statement.executeQuery(sql);
                        if (resultset_val.next()) {
                            out.print("exist");
                        }
                        break;
                    }
                    case "checkAvailability1": {
                        String category_id = request.getParameter("category_id");
                        String category_name = request.getParameter("category_name");
                        String sql = "Select category_name from course_category where category_name='" + category_name + "' and category_id!='" + category_id + "'";
                        ResultSet resultset_val = statement.executeQuery(sql);
                        if (resultset_val.next()) {
                            out.print("exist");
                        }
                        break;
                    }
                    case "checkwarning": {
                        String category_id = request.getParameter("category_id");
                        String warning = "";
                        String sql_query = "select * from course where category_id='" + category_id + "' and status='Active'";
                        ResultSet resultset_val = statement.executeQuery(sql_query);
                        if (resultset_val.next()) {
                            warning = "yes";
                        }
                        String sql_query1 = "select * from assessment where category_id='" + category_id + "' and status='Active'";
                        ResultSet resultset_val1 = statement.executeQuery(sql_query1);
                        if (resultset_val1.next()) {
                            warning = "yes";
                        }
                        if (warning.equals("yes")) {
                            throw new Exception();
                        }
                        break;
                    }
                    case "active_inactive": {
                        String category_id = request.getParameter("category_id");
                        String status = request.getParameter("status");
                        String sql = "Update course_category set status='" + status + "',last_updated_user='" + request.getSession(false).getAttribute("log_user_id") + "',last_updated_ts='" + ist.getLastUpdatedts() + "' where category_id='" + category_id + "'";
                        int i = statement.executeUpdate(sql);
                        if (i > 0) {
                        }
                        connection.commit();
                        break;
                    }
                    default:
                        break;
                }
            } catch (Exception ex) {
                Logger.getLogger(Category.class.getName()).log(Level.SEVERE, null, ex);
                try {
                    response.setStatus(400);
                    if (!connection.isClosed()) {
                        connection.rollback();
                    }
                } catch (SQLException ex1) {
                    Logger.getLogger(Category.class.getName()).log(Level.SEVERE, null, ex1);
                }
            } finally {
                try {
                    out.flush();
                    out.close();
                    if (!statement.isClosed()) {
                        statement.close();
                    }
                    if (!connection.isClosed()) {
                        connection.close();
                    }
                    statement=null;
                    connection = null;
                } catch (SQLException ex) {
                    Logger.getLogger(Category.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
            try {
                connectToServer();
                switch (request.getParameter("mode")) {
                    case "add": {
                        String category_name = request.getParameter("category_name");
                        String category_desc = request.getParameter("category_desc");
                        String status = request.getParameter("status");
                        String sql = "INSERT INTO course_category(category_name,category_desc,status,created_user,created_ts,last_updated_user,last_updated_ts) VALUES ('" + category_name + "',  '" + category_desc + "','" + status + "','" + request.getSession(false).getAttribute("log_user_id") + "','" + ist.getLastUpdatedts() + "','" + request.getSession(false).getAttribute("log_user_id") + "','" + ist.getLastUpdatedts() + "')";
                        statement.executeUpdate(sql);
                        connection.commit();
                        break;
                    }
                    case "edit": {
                        String category_id = request.getParameter("category_id");
                        String category_name = request.getParameter("category_name");
                        String category_desc = request.getParameter("category_desc");
                        String sql = "update course_category set category_name='" + category_name + "',category_desc='" + category_desc + "',last_updated_user='" + request.getSession(false).getAttribute("log_user_id") + "',last_updated_ts='" + ist.getLastUpdatedts() + "' where category_id='" + category_id + "'";
                        statement.executeUpdate(sql);
                        connection.commit();
                        break;
                    }
                    default:
                        break;
                }
            } catch (Exception ex) {
                try {
                    Logger.getLogger(Category.class.getName()).log(Level.SEVERE, null, ex);
                    if (ex instanceof SQLIntegrityConstraintViolationException) {
                        response.setStatus(1);
                    } else {
                        response.setStatus(2);
                    }
                    if (!connection.isClosed()) {
                        connection.rollback();
                    }
                } catch (SQLException ex1) {
                    Logger.getLogger(Category.class.getName()).log(Level.SEVERE, null, ex1);
                }
            } finally {
                try {
                    out.flush();
                    out.close();
                    if (!statement.isClosed()) {
                        statement.close();
                    }
                    if (!connection.isClosed()) {
                        connection.close();
                    }
                    statement=null;
                    connection = null;
                } catch (SQLException ex) {
                    Logger.getLogger(Category.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        @Override
        public String getServletInfo() {
            return "Short description";
        }
    }

如您所见,当我单击按钮时,我触发updateLists函数,该函数将进行计算以将具有已更新功能和目标按钮的新数据更改为仅发送给我们唯一的动作,并且该动作将更改状态为减速器。

featureAddedToTargets操作

class Some extends React.Component{

    constructor(props){
        super(props)
        this.state = {
            selectedFeatures:[],
            selectedTargets:[]
        }
    }

    setStateFromProps(){
        this.setState({
            selectedFeatures: this.props.features,
            selectedTargets: this.props.targets,
        }, console.log(this.state.selectedFeatures, this.state.selectedTargets))
    }

    componentDidMount(){
        this.setStateFromProps()
    }

    render(){

        const { features, targets} = this.props

        const updateLists =(selectedFeature, flag) =>{
            let index
            if  (flag){
                index = features.indexOf(selectedFeature)
                features.splice(index, 1);

                targets.push(selectedFeature)

                this.props.addFeature({features, targets})
            }else{
                index = targets.indexOf(selectedFeature)
                targets.splice(index, 1);

                features.push(selectedFeature)
                this.props.addFeature({targets, features})
            }

            console.log(this.state.selectedFeatures, this.state.selectedTargets)


        }

        return (
            <div>
                {this.state.selectedFeatures.map(feature => {

                    return <div><button key={feature} onClick={() => updateLists(feature, true)}>{feature}</button> <br /></div>
                })}
                <br />
                {this.state.selectedTargets.map(target => {
                    return <div><button key={target} onClick={() =>updateLists(target, false)} >{target}</button> <br /></div>
                })}
            </div>
        );

    }
}

const mapDispatchToProps =(dispatch) =>{
    return {
            addFeature: (data) => dispatch(featureAddedToTargets(data)),
        }
} 
const mapStateToProps= (state)=>{
    return { selectedFeature:state.addFeatureReducer.selectedFeature,
            features: state.addFeatureReducer.features,
            targets: state.addFeatureReducer.targets
    };
}


export default connect(mapStateToProps, mapDispatchToProps)(Some);

addFeatureReducer

    export const featureAddedToTargets = (data) =>{
        return {
            type: FEATURE_CHANGED,
            data
        }
    }

正如我所说,即使reducer中的initialState已经更改,因此Some组件中的道具也已更改,因此Some组件不会重新呈现,并且按钮组保持不变。我想了解为什么会这样。

enter image description here

3 个答案:

答案 0 :(得分:0)

触发动作FEATURE_CHANGED后,Reducer返回一个更新状态,该状态又通过mapStateToProps作为newProps传播到React组件。在渲染功能中,您正在this.state.selectedFeaturesthis.state.selectedTargets上进行映射。从我看来,尽管您正在获取newProps featurestargets,但您并没有在组件状态下更新它们。您可以使用getDerivedStateFromProps生命周期在新道具到达时更新状态。

getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.features !== prevState.features && nextProps.targets !== prevState.targets) {
        return ({
           selectedFeatures: nextProps.features,
           selectedTargets: nextProps.targets
        });
    }
    else if (nextProps.features !== prevState.features) {
       return ({
           selectedFeatures: nextProps.features,
        });
    } else if (nextProps.targets !== prevState.targets) {
       return ({
           selectedTargets: nextProps.targets,
        });
    }
}

您可以在这里参考:https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

答案 1 :(得分:0)

setStateFromProps(){
        this.setState({
            selectedFeatures: this.props.features,
            selectedTargets: this.props.targets,
        }, console.log(this.state.selectedFeatures, this.state.selectedTargets))
    }

尝试将其更改为

    componentDidUpdate(prevProps) {
        if(this.props.features !== prevProps.features || this.props.targets !== prevProps.targets) {
      this.setState({
            selectedFeatures: this.props.features,
            selectedTargets: this.props.targets,
        }, console.log(this.state.selectedFeatures, this.state.selectedTargets))
    }

}

答案 2 :(得分:0)

所以我弄清楚了即使状态正在更新,组件也没有更新的原因。似乎在updatedLists()中,我直接在redux存储的功能和目标数组上使用了push()和splice(),从而使状态发生了变化。由于发生了突变,因此该组件的当前状态和下一个状态均未发生变化。 React在状态中保留了两个版本-当前版本和下一个版本。它比较两者,并仅使用已更改的部分更新DOM。由于我正在改变状态,因此React在当前状态和下一个状态都相同,因此没有更新。因此,我只是更改了updatedLists(),将push()和splice()应用到了随机变量(功能和目标)中,随后将它们作为数据传递给我们的操作,并将它们的值与散布运算符(如我们之前所做的)传递给了商店的状态(initialState)。

if  (flag){
            index = this.state.selectedFeatures.indexOf(selectedFeature)
            const Features = [...this.state.selectedFeatures]
            Features.splice(index, 1);

            const Targets = [...this.state.selectedTargets]
            Targets.push(selectedFeature)

            console.log('features',features,'targets',targets)
            this.props.addFeature({features: Features , targets: Targets})
        }else{
            index = this.state.selectedTargets.indexOf(selectedFeature)
            const Targets = [...this.state.selectedTargets]
            Targets.splice(index, 1);

            const Features = [...this.state.selectedFeatures]
            Features.push(selectedFeature)

            console.log('features',features,'targets',targets)
            this.props.addFeature({ features:Features, targets: Targets})
        }