简体   繁体   English

Redux 未提供更新的 state

[英]Redux is not giving updated state

I am new to Redux.I am making an Visual Workflow platform using Reactjs, Redux & React-flow.我是 Redux 的新手。我正在使用 Reactjs、Redux 和 React-flow 制作可视化工作流平台。 User can add a node by inputting name of node and it's type in Palette (Right side as shown in picture).用户可以通过在 Palette 中输入节点名称和类型来添加节点(如图所示右侧)。 I pass the new node name and it's type to Redux dispatch.我将新节点名称及其类型传递给 Redux 调度。 Dispatching and updating the state is working fine (I have checked it by printing it on console), state is updating but I am not getting the updated state automatically just like whenever we update a hook in Reactjs it's changes are shown wherever hook variable is used. Dispatching and updating the state is working fine (I have checked it by printing it on console), state is updating but I am not getting the updated state automatically just like whenever we update a hook in Reactjs it's changes are shown wherever hook variable is used . But here it's not working like that.但在这里它不是那样工作的。 I am printing the updated state's length in top in middle div (where nodes are shown) it's only showing 0 even I add a new object to state.我在中间 div 的顶部打印更新状态的长度(显示节点),即使我将新的 object 添加到 state,它也只显示 0。

I have searched about it on internet and found that Connect function in Redux will help, I also implemented it.我在互联网上搜索过它,发现在 Redux 中连接 function 会有所帮助,我也实现了它。 But no solution.但没有解决办法。

I have been searching for it for last 2 days but can't figure out where's the problem.过去两天我一直在寻找它,但无法弄清楚问题出在哪里。 If anyone knows where's the problem, what I am missing/overlooking.如果有人知道问题出在哪里,我错过了什么/忽略了什么。 Please let me know, it will be great help.请让我知道,这将是很大的帮助。

Graph.js (where I want state to update automatically): Graph.js(我希望 state 自动更新):

import React, { useState, useEffect } from 'react';
import ReactFlow, { Controls, updateEdge, addEdge } from 'react-flow-renderer';
import { useSelector ,connect} from 'react-redux';
import input from '../actions/input';
const initialElements = [
  {
    id: '1',
    type: 'input',
    data: { label: 'Node A' },
    position: { x: 250, y: 0 },
  }]
function Graphs(props) {
  const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
  const [elements, setElements] = useState(initialElements);
  // const [state,setState]=useState(useSelector(state => state.nodeReducers))
  
  useEffect(() => {
    if (props.elements.length) {
      console.log("useEffect in", props.elements)
      setElements(els => els.push({
        id: (els.length + 1).toString(),
        type: 'input',
        data: props.elements.data,
        position: props.elements.position
      }));
      return;
    }
    console.log("outside if ",props.elements)
  }, [props.elements.length])
  const onEdgeUpdate = (oldEdge, newConnection) =>
    setElements((els) => updateEdge(oldEdge, newConnection, els));
  const onConnect = (params) => setElements((els) => addEdge(params, els));
  return (
    <ReactFlow
      elements={elements}
      onLoad={onLoad}
      snapToGrid
      onEdgeUpdate={onEdgeUpdate}
      onConnect={onConnect}
    >
      {console.log("in main", props.elements)}
      <Controls />
      <p>hello props {props.elements.length}</p>
    </ReactFlow>

  )
}
const mapStateToProps=state=>{
  return{
    elements:state.nodeReducers
  }
}
const mapDisptachToProps=dispatch=>{
  return{
    nodedispatch:()=>dispatch(input())
  }
}
export default connect(mapStateToProps,mapDisptachToProps)(Graphs);

nodeReducers.js (Reducer): nodeReducers.js(减速器):

const nodeReducers=(state=[],action)=>{
      switch (action.type) {
            case "ADD":
                  state.push(...state,action.NodeData)
                  console.log("in node reducers",state)
                  return state;
            default:
                  return state;
      }
}
export default nodeReducers;

input.js(Action): input.js(动作):

const input = (obj = {}) => {
      console.log("in action",obj)
      return {
            type: "ADD",
            NodeData: {
                  type: 'input',
                  data: { label: obj.NodeValue },
                  position: { x: 250, y: 0 }
            }
      }
}
export default input;

PaletteDiv.js (Right side palette div where I take user input): PaletteDiv.js(我接受用户输入的右侧调色板 div):

import React, { useState } from 'react'
import '../styles/compoStyles/PaletteDiv.css';
import { makeStyles } from '@material-ui/core/styles';
import { FormControl, TextField, InputLabel, Select, MenuItem, Button } from '@material-ui/core';
import {  connect } from 'react-redux';
import input from '../actions/input';
function PaletteDiv(props) {
      const [nodename, setNodename] = useState();
      const [nodetype, setNodetype] = useState();
      const [nodevalue, setNodevalue] = React.useState('');

      const handleChange = (event) => {
            setNodevalue(event.target.value);
            setNodetype(event.target.value);
      };

      const useStyles = makeStyles((theme) => ({
            margin: {
                  margin: theme.spacing(1),
                  width: "88%"
            },
            formControl: {
                  margin: theme.spacing(1),
                  minWidth: 120,
            },
            selectEmpty: {
                  marginTop: theme.spacing(2),
            }
      }));

      const styles = {
            saveb: {
                  float: "left",
                  margin: "auto"
            },
            cancelb: {
                  float: "right"
            },
            inputfield: {
                  display: "block",
                  width: "100%",
                  margin: "0"
            }
      }
      const classes = useStyles();
      const useStyle = makeStyles(styles);
      const css = useStyle();
      return (
            <div id="myPaletteDiv">
                  <div className="heading">
                        <h1>Palette</h1>
                  </div>
                  <div className="palette">
                        <label >WorkFlow Name</label>
                        <TextField id="outlined-basic" fullwidth className={css.inputfield} variant="outlined" onChange={e => setNodename(e.target.value)} />
                        <label >Type of Node</label>
                        <FormControl variant="outlined" className={classes.formControl}>
                              <InputLabel id="demo-simple-select-outlined-label">Node</InputLabel>
                              <Select
                                    labelId="demo-simple-select-outlined-label"
                                    id="demo-simple-select-outlined"
                                    value={nodevalue}
                                    onChange={handleChange}
                                    label="Age"
                              >
                                    <MenuItem value="">
                                          <em>None</em>
                                    </MenuItem>
                                    <MenuItem value={10}>Step</MenuItem>
                                    <MenuItem value={20}>Condition</MenuItem>
                              </Select>
                              <Button variant="contained" color="primary" onClick={(e) => {
                             e.preventDefault();   
                      const node = { 
                                          NodeType: nodetype,
                                          NodeValue: nodename
                                    }
                                    props.nodedispatch(node)
                                    console.log("done dispatching")
                              }}>
                                    Add Node
                              </Button>
                        </FormControl>
                  </div>
            </div>
      )
}

const mapStateToProps = state => {
      return {
            elements: state.nodeReducers
      }
}
const mapDisptachToProps = dispatch => {
      return {
            nodedispatch: (node) => dispatch(input(node))
      }
}
export default connect(mapStateToProps, mapDisptachToProps)(PaletteDiv);

ScreenShot:截屏: 在此处输入图像描述

Here you can see I have a在这里你可以看到我有一个

tag in middle div's top.标签在中间 div 的顶部。 It's showing "hello props 0".它显示“你好道具 0”。 I want 0 (zero) to change whenever I add a node.每当我添加一个节点时,我都希望 0(零)发生变化。

Thanking You感谢您

Yours Truly,敬上,

Rishabh Raghwendra里沙布·拉格温德拉

Don't push a data directly into a state into state, instead reassign the state using spreading operators不要将数据直接推送到 state 到 state 中,而是使用扩展运算符重新分配 state

const nodeReducers = (state = [],action) => {
      switch (action.type) {
            case "ADD":
                  state = [...state, action.NodeData];
                  console.log("in node reducers",state);
                  return state;
            default:
                  return state;
      }
}
export default nodeReducers;

It's because your reducers must be pure functions.这是因为您的减速器必须是纯函数。 Reducer must work with the state, like with immutable data. Reducer 必须与 state 一起使用,就像不可变数据一样。 You have to avoid side effects in your reducers你必须避免减速器的副作用

https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers#rules-of-reducers https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers#rules-of-reducers

I agree with the previous answer, but, as I said earlier, here we can avoid side effect like reassing:我同意前面的答案,但是,正如我之前所说,在这里我们可以避免像重新评估这样的副作用:

const nodeReducers = (state = [],action) => {
      switch (action.type) {
            case "ADD":
                  return [...state, action.NodeData];
            default:
                  return state;
      }
}
export default nodeReducers;

Also, according to the best practices, highly recommended to write your action types to constants and use them in your actions and reducers instead of strings.此外,根据最佳实践,强烈建议将您的操作类型写入常量,并在您的操作和减速器中使用它们而不是字符串。

// actionTypes.js
export const ADD = "ADD";
// then import it in your reducer and action

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM