如何根据用户输入将对象推送到状态数组

how to push an object to a state array based on user input

我有一个 table 每行都有文本框,我想识别它们中的每一个

我需要将“task”和“setTask”从简单的字符串更改为一个对象数组,该数组可以为每一行获取用户输入并将其添加为对象 {id, value}(稍后使用)

这是一个工作示例:https://codesandbox.io/s/dawn-wildflower-cfvol?file=/src/App.js

  1. 单击“开始扫描”按钮(它将加载网格)
  2. 点击“写一个任务名称”中的任何一个(它将打开所有记录)

我需要的是:只为特定记录打开,handleChange 需要将对象推入数组而不是字符串

代码:

import { useState } from "react";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import { makeStyles, withStyles } from "@material-ui/core/styles";
import { Typography } from "@material-ui/core";
import Button from "@material-ui/core/Button";

const useStyles = makeStyles((theme) => ({
container: {
  maxHeight: 440,
  width: "100%"
},
}));

const StyledTableCell = withStyles((theme) => ({
head: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white
},
body: {
fontSize: 14
}
}))(TableCell);
const StyledTableRow = withStyles((theme) => ({
root: {
"&:nth-of-type(odd)": {
  backgroundColor: theme.palette.action.hover
}
}
}))(TableRow);

 export default function CommentTest(
 )  {
const classes = useStyles();
const [bulkScanList, setBulkScanList] = useState([]);
const [name, setname] = useState([]);  
const [openId, setOpenId] = useState();
const [editMode, setEditMode] = useState(false);
const [task, setTask] = useState("");
const data = {
samples: [
  {
    sampleContainers: [
      {
        id: 4447,
        sampleId: 2656,
        code: "00JC",
        color: "Green",
        name: "250g Soil Jar",
        description: "250g Soil Jar",
        containerId: 1,
        comments: "",
        barcode: "00JC001180",
        testLists: null,
        isStandardContainer: true,
        preservationType: "none",
        scanStatus: 1,
        srComments: null
      }
    ],
    id: 2656,
    batchId: 1499,
    sampleName: "COC_SCA",
    dateSampled: "2021-12-21T10:46:00",
    matrixId: 2
  },
  {
    sampleContainers: [
      {
        id: 4448,
        sampleId: 2657,
        code: "00JC",
        color: "Green",
        name: "250g Soil Jar",
        description: "250g Soil Jar",
        containerId: 1,
        comments: "",
        barcode: "00JC001182",
        testLists: null,
        isStandardContainer: true,
        preservationType: "none",
        scanStatus: 1,
        srComments: null
      }
    ],
    id: 2657,
    batchId: 1499,
    sampleName: "COC_SCA",
    dateSampled: "2021-12-21T10:46:00",
    matrixId: 2
  },
  {
    sampleContainers: [
      {
        id: 4449,
        sampleId: 2658,
        code: "00JC",
        color: "Green",
        name: "250g Soil Jar",
        description: "250g Soil Jar",
        containerId: 1,
        comments: "",
        barcode: "00JC001179",
        testLists: null,
        isStandardContainer: true,
        preservationType: "none",
        scanStatus: null,
        srComments: "check"
      }
    ],
    id: 2658,
    batchId: 1499,
    sampleName: "COC_SCA",
    dateSampled: "2021-12-21T10:46:00",
    matrixId: 2
  },
  {
    sampleContainers: [
      {
        id: 4450,
        sampleId: 2659,
        code: "00JC",
        color: "Green",
        name: "250g Soil Jar",
        description: "250g Soil Jar",
        containerId: 1,
        comments: "",
        barcode: "00JC001181",
        testLists: null,
        isStandardContainer: true,
        preservationType: "none",
        scanStatus: null,
        srComments: "comment"
      }
    ],
    id: 2659,
    batchId: 1499,
    sampleName: "COC_SCA",
    dateSampled: "2021-12-21T10:46:00",
    matrixId: 2
  },
  {
    sampleContainers: [
      {
        id: 4451,
        sampleId: 2660,
        code: "00JC",
        color: "Green",
        name: "250g Soil Jar",
        description: "250g Soil Jar",
        containerId: 1,
        comments: "",
        barcode: "00JC001183",
        testLists: null,
        isStandardContainer: true,
        preservationType: "none",
        scanStatus: null,
        srComments: null
      }
    ],
    id: 2660,
    batchId: 1499,
    sampleName: "COC_SCA",
    dateSampled: "2021-12-21T10:46:00",
    matrixId: 2
  }
]
};

const handleKeyDown = (event, type) => {
// Handle when key is pressed
};

const retrieveBulkScanList = (e) => {

const sampleNames = data?.samples.map((x) => ({
  name: x.sampleName,
  id: x.id
}));
const containers = data?.samples
  .map((x) => x.sampleContainers)
  .flat()
  .map((elm) => elm);
console.log('retrieve bulk scan');
setname([...sampleNames]);
setBulkScanList([...containers]);

};

const handleChange = (e, container) => {
  const { value, id } = e.currentTarget;
  setTask(value);
  console.log("comments added: " + value + " id: " + id);
}

return (
<div className="App">
  <h1>Hello CodeSandbox</h1>
  <TableContainer className={classes.container}>
    <Table className={classes.table} stickyHeader aria-label="sticky table">
      <TableHead>
        <TableRow>
          <TableCell>
            <Typography variant="h6">Sample Name</Typography>
          </TableCell>
          <TableCell align="right">
            <Typography variant="h6">Container Name</Typography>
          </TableCell>
          <TableCell align="right">
            <Typography variant="h6">SR Comments</Typography>
          </TableCell>
        </TableRow>
      </TableHead>
      <TableBody>
        {bulkScanList.length === 0 ? (
          <div>Scan to fetch data...</div>
        ) : (
          bulkScanList
            .slice(0)
            .reverse()
            .map((x) => (
              <StyledTableRow key={x.id.toString()}>
                <StyledTableCell component="th" scope="row">
                  {name
                    .filter((n) => n.id === x.sampleId)
                    .map((e) => e.name)}
                  _{x.sampleId}
                </StyledTableCell>
                <StyledTableCell align="right">{x.name}</StyledTableCell>
                <StyledTableCell>
                {editMode ? (
    <div
      onBlur={() => setEditMode(false)}
      onKeyDown={e => handleKeyDown(e, "input")}
    >
     <input
    type="text"
    name="task"
    placeholder="Write a task name"
    value={task}
    onChange={e => handleChange(e, x)}
  />
    </div>
  ) : (
    <div
      onClick={() => setEditMode(true)}
    >
      <span>
        {task || "Write a task name" || "Editable content"}
      </span>
    </div>
  )}
                </StyledTableCell>
              </StyledTableRow>
            ))
        )}
      </TableBody>
    </Table>
  </TableContainer>
  <Button
    color="primary"
    style={{ height: "50%", borderRadius: "30px" }}
    onClick={retrieveBulkScanList}
  >
    Start Scan
  </Button>
</div>
);
}

要将一个对象推送到一个已经存在的状态数组,您可以使用:

setState((oldArray) => [...oldArray, newObj]);

要映射对象的完整状态数组,您可以使用:

{state && state.map(({ id, value}) => (
    <div>{id}</div>
    <div>{value}</div>
))}

我终于解决了..这是一个工作代码示例https://codesandbox.io/s/happy-framework-e27gl?file=/src/App.js

基本上我改了4个地方

  1. 更改为以下内容

     { 
            Object.values(task).filter((c) => c.id == x.id).length > 0 ? 
             Object.values(task).filter((c) => c.id == x.id).map(obj =>  
               <input
               id={x.id}
               type="text"
               name="task"
               placeholder="Write a task name"
               value={obj.value}
               onChange={e => handleChange(e, x)}
           />)
           :
      <input
               id={x.id}
               type="text"
               name="task"
               placeholder="I am duplicate"
               onChange={e => handleChange(e, x)}
           />
    
         }
    
  2. 更改{任务|| “写一个任务名称……”到下面

    <span>{
       Object.values(task).filter((c) => c.id == x.id).length > 0 ? 
             Object.values(task).filter((c) => c.id == x.id).map(obj =>
         obj.value) : "I am the span" }
       </span>
    

这个问题花了我一整天的时间来排序,因为 jsx 没有指出正确的错误,我继续修复其他地方..它只是给我以下错误

Error: Objects are not valid as a React child (found: object with keys {id, value}).

P.S: 另外我在我的代码中用 obj 替换了 {id, value}

  1. 这个很直接

    const [task, setTask] = useState([]);
    
  2. 这就是魔法! (虽然很麻烦)

    const handleChange = (e, container) => {
    const { value, id } = e.currentTarget;
    const oldArray = Object.values(task);
    const pos = oldArray.map(function(e) { return e.id; }).indexOf(container.id);
    console.log('position: ' + pos);
    
    const matched = oldArray.filter(c => c.id === container.id);
    
    if(matched.length > 0){
     oldArray[pos] =  {"id": container.id, "value":value};
     setTask(oldArray);
     console.log("hey")
    }
    else{
     var newStateArray = oldArray.slice();
     newStateArray.push({"id": container.id, "value":value});
     setTask(newStateArray);
     console.log("comments added: " + value + " id: " + container.id);
    
    }
    
    }