当前位置: 首页 > 知识库问答 >
问题:

更新

曾永新
2023-03-14

我有一个表单,其中用户创建了一个编码问题。在表单中,可以通过输入和输出文本框添加示例测试用例。用户可以单击按钮添加新的测试用例。现在我有一个state对象,它保存所有表单数据formObj,其中有一个示例_test_cases字段,我想保存一个对象数组,比如:[{input:,output::}]。

我遇到的问题是更新此阵列。我需要能够在每次添加测试用例时将一个新对象连接到它。然后在文本框更改时更新该索引处的状态。我尝试创建一个无状态数组并对其进行更新,然后将sample\u test\u案例设置到该数组中。然而,这是行不通的。

这是一个沙盒,上面有我的代码:https://codesandbox.io/s/eloquent-snowflake-n4bpl?file=/src/AddProblemForm.js

如果有人能给我一些有用的建议。我不太熟悉Javascript或复杂的状态管理。谢谢

共有2个答案

宿淳
2023-03-14

我建议您在状态复杂的情况下使用useReducer钩子。

钩子API

当您有涉及多个子值的复杂状态逻辑时,或者当下一个状态依赖于前一个状态时,useReucer通常比useState更可取。

addProblemForm.js:

import React, { useReducer } from "react";
import { Form, Button, Col } from "react-bootstrap";
import { BsPlusSquare } from "react-icons/bs";
import SampleTestCase from "./SampleTestCase";

const initialState = {
  sample_test_cases: [],
  counter: 0
  // other state obj info
};
function reducer(state, action) {
  switch (action.type) {
    case "addSampleTestCase": {
      const { data } = action;
      return {
        ...state,
        sample_test_cases: [...state.sample_test_cases, data],
        counter: state.counter + 1
      };
    }
    case "updateTest": {
      const { index, value } = action;
      return {
        ...state,
        sample_test_cases: state.sample_test_cases.map((item, i) => {
          if (i === index) {
            return value;
          } else {
            return item;
          }
        })
      };
    }

    default:
      throw new Error();
  }
}

const AddProblemForm = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  const AddSampleTestCase = () => {
    dispatch({ type: "addSampleTestCase", data: { input: "", output: "" } });
  };

  /* console.log(state); */

  return (
    <div>
      Problem Form
      <Form>
        <h5 style={{ paddingTop: "1rem" }}>Sample Test Cases</h5>
        {state.sample_test_cases.map((sample_test_case, i) => (
          <div key={i}>
            <SampleTestCase
              sample_test_case={sample_test_case}
              updateValue={(value) =>
                dispatch({ type: "updateTest", index: i, value })
              }
            />
            <hr />
          </div>
        ))}
        <Button onClick={AddSampleTestCase}>
          <div>Add Sample Test Case</div>
        </Button>
      </Form>
    </div>
  );
};

export default AddProblemForm;

SampleTestCase.js

import React from "react";
import { Form, Button, Col } from "react-bootstrap";

const SampleTestCase = ({ sample_test_case, updateValue }) => {
  return (
    <Form.Row>
      <Col>
        <Form.Group controlId="input">
          <Form.Label>Sample Input</Form.Label>
          <Form.Control
            required
            as="textarea"
            rows={2}
            value={sample_test_case.input}
            onChange={(event) => updateValue(event.target.value)}
          />
        </Form.Group>
      </Col>
      <Col>
        <Form.Group controlId="output">
          <Form.Label>Sample Output</Form.Label>
          <Form.Control
            required
            as="textarea"
            rows={2}
            value={sample_test_case.output}
            onChange={(event) => updateValue(event.target.value)}
          />
        </Form.Group>
      </Col>
    </Form.Row>
  );
};
export default SampleTestCase;
龚远
2023-03-14

请参阅下面的片段(我在保存沙箱时遇到问题)。它解决的几个问题:

  1. 您还使用一些本地arr变量跟踪状态;更新不会触发重新渲染,因此您需要修改formObj状态中的sample\u test\u cases数组。
  2. textarea也应该反映您的状态。为了方便起见,我将测试用例作为道具传递到SampleTestCase组件中,因此它将对状态更改做出反应。
  3. 应将React状态视为不可变。因此,当更新输入文本框时,您应该使用新的示例测试案例数组将状态设置为新对象,该数组由第一个i-1测试案例、修改输入的第i个新测试案例以及其余测试案例构成。
  4. SampleTestCase移到AddProblemForm组件之外。如果你不这样做,你会发现每当输入文本区域被改变时,你就会失去键盘的焦点。这是因为将在每个渲染上重新定义SampleTestCase组件,该组件由状态更改触发。(类似的问题:React.js-重新提交时输入失去焦点)
import React, { useState } from "react";
import { Form, Button, Col } from "react-bootstrap";
import { BsPlusSquare } from "react-icons/bs";

const SampleTestCase = ({ testCase, updateInput }) => {
  return (
    <Form.Row>
      <Col>
        <Form.Group controlId="input">
          <Form.Label>Sample Input</Form.Label>
          <Form.Control
            required
            as="textarea"
            rows={2}
            onChange={updateInput}
            value={testCase.input}
          />
        </Form.Group>
      </Col>
      <Col>
        <Form.Group controlId="output">
          <Form.Label>Sample Output</Form.Label>
          <Form.Control
            required
            as="textarea"
            rows={2}
            // onChange={(event) =>
            //   setFormObj({
            //     ...formObj,
            //     sample_test_cases: {
            //       ...formObj.sample_test_cases,
            //       output: event.target.value
            //     }
            //   })
            // }
          />
        </Form.Group>
      </Col>
    </Form.Row>
  );
};

const AddProblemForm = () => {
  const [formObj, setFormObj] = useState({
    sample_test_cases: [{ input: "", output: "" }]
    // other state obj info
  });

  const AddSampleTestCase = () => {
    // make new instance!
    const newTestCase = { input: "", output: "" };
    setFormObj({
      ...formObj,
      sample_test_cases: [...formObj.sample_test_cases, newTestCase]
    });
  };

  console.log(formObj);

  const updateInputFor = (i) => (event) => {
    event.preventDefault();

    const { sample_test_cases } = formObj;
    const testCase = sample_test_cases[i];
    testCase.input = event.target.value;

    setFormObj({
      ...formObj,
      sample_test_cases: [
        ...sample_test_cases.slice(0, i),
        testCase,
        ...sample_test_cases.slice(i + 1)
      ]
    });
  };

  return (
    <div>
      Problem Form
      <Form>
        <h5 style={{ paddingTop: "1rem" }}>Sample Test Cases</h5>
        {formObj.sample_test_cases.map((testCase, i) => (
          <React.Fragment key={i}>
            <SampleTestCase
              key={i}
              testCase={testCase}
              updateInput={updateInputFor(i)}
            />
            <hr />
          </React.Fragment>
        ))}
        <Button onClick={AddSampleTestCase}>
          <div>Add Sample Test Case</div>
        </Button>
      </Form>
    </div>
  );
};

export default AddProblemForm;
 类似资料:
  • 我有一个问题与primeface数据表。我有一个数据与一些条目和一个列与一个按钮内。如果按钮被按下,一个弹出窗口打开与另一个数据表。第二个数据表中的条目取决于行中的按钮被按下。 Bean2 问题是弹出式数据表中没有列出任何条目,尽管在db查询之后的列表中有一些条目。 有没有办法修复这个bug?提前感谢! 更新1:

  • 我们使用liquibase对数据库进行源代码控制。最初,我们从Postgres开始,创建了数据类型为特定于Postgres的列的变更集。 例如,我们有一个变更集,它创建了具有“JSON”类型字段的表。现在,我们想转移到其他数据库。因此,当我们针对另一个数据库运行变更集时,它无法创建表。我尝试添加“failOnError=false”。但是,后面的变更集失败,因为该表不存在。 您能建议如何重构旧的变

  • Flarum 正处于测试阶段,有关如何更新的说明将在每次 版本发布公告中公示。

  • 如果你想和社区以及开发版的 Requests 保持最新的联系, 这有几种方式: GitHub 最好的方式是追踪 Requests 开发版本的 GitHub 库. Twitter 我经常推送关于 Requests 的新功能和新版本. 关注 @kennethreitz 即可获得更新。 Release History dev Improvements Bugfixes 2.18.1 (2017-06-1

  • 和模型新增一样,更新操作同样也会经过修改器、自动完成以及模型事件等处理,并不等同于数据库的数据更新,而且更新方法和新增方法使用的是同一个方法,通常系统会自动判断需要新增还是更新数据。 查找并更新 在取出数据后,更改字段内容后使用save方法更新数据。这种方式是最佳的更新方式。 $user = User::get(1); $user->name = 'thinkphp'; $user->em

  • Yearning采用自动表结构同步 无需手动更新表结构。只需停止原服务并替换安装包后重新启动即可 在一些特殊的升级情况中(破坏性变更)需要手动进行数据同步操作.如在版本更新公告中并无提示破坏性升级则无视以下命令! ./Yearning migrate