【问题标题】:Redux is not giving updated stateRedux 没有提供更新的状态
【发布时间】:2021-02-03 12:50:35
【问题描述】:

我是 Redux 的新手。我正在使用 Reactjs、Redux 和 React-flow 制作一个可视化工作流平台。用户可以通过在 Palette 中输入节点名称和类型来添加节点(如图所示右侧)。我将新节点名称及其类型传递给 Redux dispatch 。调度和更新状态工作正常(我已经通过在控制台上打印它来检查它),状态正在更新,但我没有自动获取更新的状态,就像每当我们在 Reactjs 中更新一个钩子时,它的更改都会显示在使用钩子变量的任何地方.但在这里它不是那样工作的。我在中间 div 的顶部打印更新后的状态长度(显示节点),即使我向状态添加新对象,它也只显示 0。

我在网上搜索了一下,发现 Redux 中的 Connect 功能会有所帮助,我也实现了它。但没有解决办法。

过去 2 天我一直在寻找它,但无法弄清楚问题出在哪里。 如果有人知道问题出在哪里,我缺少/忽略了什么。请告诉我,这将是很大的帮助。

Graph.js(我希望状态自动更新):

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(减速器):

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(动作):

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(我接受用户输入的右侧调色板 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);

屏幕截图:

在这里你可以看到我有一个

标签在中间 div 的顶部。它显示“你好道具 0”。我希望在添加节点时更改 0(零)。

谢谢你

真诚的,

Rishabh Raghwendra

【问题讨论】:

  • 你能在你nodeReducer 'ADD' 的情况下尝试return [...state, action.NodeData]; 吗?
  • @SreekarMouli 我已经在我的代码中应用了你的方式,但是在显示更新状态后,应用程序突然崩溃了。我不知道问题出在哪里。我在上面添加了 PaletteDiv.js,用于将数据输入到 Redux 存储中。请看,是否有任何错误或我留下的东西?

标签: javascript reactjs redux


【解决方案1】:

不要将数据直接推入状态,而是使用扩展运算符重新分配状态

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;

【讨论】:

  • 我按照你说的应用了扩展运算符,“hello props 0”更改为“hello props 2”(我不知道为什么它显示 2 而不是输入 1 节点),然后突然我应用程序坏了。屏幕上的一切都消失了。我在上面的帖子中添加了 PaletteDiv.js 代码。请告诉redux store输入值是否有问题? .谢谢
【解决方案2】:

这是因为你的 reducer 必须是纯函数。 Reducer 必须与状态一起工作,就像不可变数据一样。您必须避免减速器的副作用

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

我同意前面的答案,但是,正如我之前所说,在这里我们可以避免像重新评估这样的副作用:

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

此外,根据最佳实践,强烈建议将您的操作类型写入常量,并在您的操作和化简器中使用它们而不是字符串。

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

【讨论】:

  • 感谢您的建议。根据我正在做的,我正在关注 Redux 上的 Youtube 上的视频教程。
  • 在显示更新状态后,我使用了扩展运算符,因为我的应用程序突然崩溃了。我不知道问题出在哪里。我还在我的帖子中添加了上面的 PaletteDiv.js,我曾经将一个节点输入到 redux store 中。请看,是否有任何问题是由于我输入时哪个应用程序崩溃了?
  • 使用 google chrome 的 redux dev tools 扩展来调试你的 react-redux 应用 chrome.google.com/webstore/detail/redux-devtools/… 在这个扩展中,你可以追踪 action 是如何与 reducer 一起工作的以及出了什么问题
  • 我添加了扩展 Redux devtools 并下载了它的包,但它显示错误“连接建立错误:net::ERR_CERT_DATE_INVALID”..
  • @DimtryVdovichemko 它在控制台中显示“TypeError: propElements.forEach is not a function”。并且页面变成纯白的空白
猜你喜欢
  • 2021-09-08
  • 1970-01-01
  • 2018-03-08
  • 2019-05-15
  • 2019-03-26
  • 2021-03-21
  • 2020-05-23
  • 2018-07-21
相关资源
最近更新 更多