Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React setState hook未在循环外更新_Javascript_Reactjs_For Loop_React Hooks_Setstate - Fatal编程技术网

Javascript React setState hook未在循环外更新

Javascript React setState hook未在循环外更新,javascript,reactjs,for-loop,react-hooks,setstate,Javascript,Reactjs,For Loop,React Hooks,Setstate,更新: 这就是一个例子 我有一个textarea组件,我在其中逐行执行验证: UI中的错误消息是一组对象,这些对象具有基于文本所在行的id属性和包含错误的消息属性例如{id:1,消息:“错误消息”,名称:“第行文本”} 据我所知,不能在循环中设置状态,因为结果不能保证 这是获取字符串的setMessage函数: 正在我的验证函数内调用setMessage: function setMessage(data) { console.log('data', data); consol

更新:

这就是一个例子

我有一个textarea组件,我在其中逐行执行验证:

UI中的错误消息是一组对象,这些对象具有基于文本所在行的id属性和包含错误的消息属性<代码>例如{id:1,消息:“错误消息”,名称:“第行文本”}

据我所知,不能在循环中设置状态,因为结果不能保证

这是获取字符串的setMessage函数:

正在我的验证函数内调用setMessage:

function setMessage(data) {
    console.log('data', data);
    console.log("arrFromVariableTypeNameString ", arrFromVariableTypeNameString);
    let allMessages = [...messagesContainer];

    function drop(data, func) {
        var result = [];
        for (var i = 0; i < data.length; i++) {
            var check = func(data[i]);
            console.log("check ", check);
            if (check) {

                console.log("i + 1 ", i + 1);
                result = data.slice(i, i + 1);
                break;
            }
        }
        return result;
    }

    for (var i = 0; i < arrFromVariableTypeNameString.length; i++) {

        var match = drop(allMessages, e => e.id === i + 1);

        if (match?.length) {
            match[0] = {
                ...match[0],
                ...{
                    message: data,
                    name: arrFromVariableTypeNameString[i]
                }
            }

            console.log("match ", match);
            console.log("allMessages ", allMessages);

            allMessages = allMessages.map(t1 => ({
                ...t1,
                ...match.find(t2 => {
                    console.log("t2.id === t1.id ", t2.id === t1.id);
                    return t2.id === t1.id
                })
            }))


        } else {
            allMessages.push({
                name: arrFromVariableTypeNameString[i],
                id: i + 1,
                message: data
            })
        }
    }

    setMessagesContainer(allMessages)
}
函数设置消息(数据){
console.log('data',data);
log(“arrFromVariableTypeNameString”,arrFromVariableTypeNameString);
让allMessages=[…messagesContainer];
函数删除(数据,函数){
var结果=[];
对于(变量i=0;ie.id==i+1);
如果(匹配?长度){
匹配[0]={
…匹配[0],
...{
信息:数据,
名称:arrFromVariableTypeNameString[i]
}
}
控制台日志(“匹配”,匹配);
日志(“所有消息”,所有消息);
allMessages=allMessages.map(t1=>({
…t1,
…匹配。查找(t2=>{
log(“t2.id==t1.id”,t2.id==t1.id);
返回t2.id==t1.id
})
}))
}否则{
allMessages.push({
名称:arrFromVariableTypeNameString[i],
id:i+1,
信息:数据
})
}
}
设置消息容器(所有消息)
}
这是整个组件:

导出函数变量setupmodal({
现有可变类型
}) {
const dispatch=usedpatch();
常量[isOpen,setIsOpen]=useState();
const[variableTypeName,setVariableTypeName]=useState(“”);
常量[clipboardData,setClipboardData]=useState(“”)
常量[pasted,setIsPasted]=useState(false)
const[messages,setMessages]=useState(“”);
const[messagesContainer,setMessagesContainer]=useState([]);
var arrFromVariableTypeNameString=variableTypeName.split('\n');
useffect(()=>{
函数设置消息(数据){
console.log('data',data);
log(“arrFromVariableTypeNameString”,arrFromVariableTypeNameString);
让allMessages=[…messagesContainer];
函数删除(数据,函数){
var结果=[];
对于(变量i=0;ie.id==i+1);
如果(匹配?长度){
匹配[0]={…匹配[0],
...{
信息:数据,
名称:arrFromVariableTypeNameString[i]
}
}
控制台日志(“匹配”,匹配);
日志(“所有消息”,所有消息);
allMessages=allMessages.map(t1=>({…t1,
…匹配。查找(t2=>{
log(“t2.id==t1.id”,t2.id==t1.id);
返回t2.id==t1.id
})
}))
}否则{
allMessages.push({
名称:arrFromVariableTypeNameString[i],
id:i+1,
信息:数据
})
}
}
设置消息容器(所有消息)
}
函数验证器(variableType){
风险值数据={
variableType:variableType,
}
风险值规则={
变量类型:“正则表达式:^[a-zA-Z0-9+$|最小值:3 |最大值:20”,
}
变量消息={
min:`至少输入三个字符。`,
马克斯:“不要超过二十个字符。”,
regex:`不允许使用特殊字符(但空格)`
}
验证(数据、规则、消息)
。然后(成功=>{
console.log('变量类型输入正确',成功)
setMessage(“”);
返回
})
.catch(错误=>{
console.log('error',error)
setMessage(错误[0]。消息);
返回
});
}
函数检查阵列唯一(myArray){
if(myArray.length==50)setMessages('只允许50种变量类型');
返回myArray.length==新集合(myArray.size);
}
arrFromVariableTypeNameString.map((variableType,i,thisArr)=>{
函数查找副本(唯一计数){
变量计数={},
结果='';
uniqueCount.forEach((i)=>{
计数[i]=(计数[i]| 0)+1;
});
控制台日志(计数);
返回Object.keys(count).map((k)=>{
if(count[k]>1)返回result.concat(`Variable Type${k}:出现${count[k]}次。`)
}).filter((项)=>项!==未定义)
}
如果(检查阵列唯一性(此阵列)){
if(验证器(可变类型)){
const setMessageForLine = (message, lineNumber) => {
  setMessagesContainer((existing) => [
    ...existing.slice(0, lineNumber),
    message,
    ...existing.slice(lineNumber + 1)
  ]);
}
import "./styles.css";
import React, { useEffect, useState, useRef, useCallback } from "react";
import { validate } from "indicative/validator";

export function TextArea({ onSave }) {
  const [variableTypeName, setVariableTypeName] = useState("");
  const [clipboardData, setClipboardData] = useState("");
  const [pasted, setIsPasted] = useState(false);
  const [messagesContainer, setMessagesContainer] = useState([]);

  // don't need to validate the same text more than once
  const lastCheckedLines = useRef([]);

const setMessageForLine = useCallback(
  (message, lineNumber) => {
    setMessagesContainer((existing) => [
      ...existing.slice(0, lineNumber),
      message,
      ...existing.slice(lineNumber + 1)
    ]);
  },
  [setMessagesContainer]
);

  const getLineError = useCallback(
    (text, index, all) => {
      // if too many lines
      if (index >= 50) {
        return "Only 50 Variable Types allowed.";
      }

      // blank lines will show up as duplicates of each other
      if (text.length === 0) {
        return "No empty lines";
      }

      // check if this line is the same as any of the previous
      const duplicateOf = all.slice(0, index).findIndex((v) => v === text);
      if (duplicateOf !== -1) {
        return `Duplicate of line ${duplicateOf + 1}`;
      }
    },
    []
  );

  const asyncValidateLine = useCallback(
    (text, index) => {
      var data = {
        variableType: text
      };

      var rules = {
        variableType: "regex:^[a-zA-Z0-9_ ]+$|min:3|max:20"
      };

      var messages = {
        min: `Enter at least three characters.`,
        max: `Don't exceed more than twenty characters.`,
        regex: `No special characters (but spaces) allowed.`
      };

      validate(data, rules, messages)
        .then((success) => {
          console.log("Variable Type Entered correctly.", success);
          setMessageForLine("", index);
        })
        .catch((error) => {
          console.log("error", error);
          setMessageForLine(error[0].message, index);
        });
    },
    [setMessageForLine]
  );

  useEffect(() => {
    const lineTexts = variableTypeName.split("\n");

    // remove extra lines when deleting
    setMessagesContainer((existing) =>
      existing.length > lineTexts.length
        ? existing.slice(0, lineTexts.length)
        : existing
    );

    lineTexts.forEach((text, i) => {
      // only check if we have a new text
      if (text !== lastCheckedLines.current[i]) {
        console.log(`evaluating line ${i + 1}`);
        const error = getLineError(text, i, lineTexts);
        if (error) {
          setMessageForLine(error, i);
        } else {
          asyncValidateLine(text, i);
        }
      }
    });

    lastCheckedLines.current = lineTexts;
  }, [variableTypeName, getLineError, asyncValidateLine, setMessageForLine, setMessagesContainer]);

  const handlePaster = (e) => {
    e.persist();

    setIsPasted(true);
    setClipboardData(e.clipboardData.getData("text"));
  };

  const handleChange = (e) => {
    e.persist();
    var { keyCode } = e;
    var { value } = e.target;

    if (keyCode === 13) {
      setVariableTypeName(`${value}\n`);
      return;
    } else if (pasted === true && keyCode === 13) {
      setVariableTypeName(`${variableTypeName.concat(clipboardData)}\n`);
      setIsPasted(false);
      return;
    } else if (pasted === true && keyCode !== 13) {
      setVariableTypeName(`${variableTypeName.concat(clipboardData)}`);
      setIsPasted(false);
      return;
    } else {
      setVariableTypeName(`${value}`);
      return;
    }
  };

  return (
    <div>
      <textarea
        placeholder="Variable Types"
        maxLength={100}
        value={variableTypeName}
        onPaste={(e) => handlePaster(e)}
        onChange={(e) => handleChange(e)}
      />

      {messagesContainer.map((message, i, arr) => {
        console.log("message ", message);
        return message ? (
          <p key={i} className="Messages">{`Error on line ${
            i + 1
          }: ${message}`}</p>
        ) : null;
      })}
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <TextArea onSave={console.log} />
    </div>
  );
}
import "./styles.css";
import React, { useEffect, useState, useCallback } from "react";

export function TextArea({ onSave }) {
  const [variableTypeName, setVariableTypeName] = useState("");
  const [clipboardData, setClipboardData] = useState("");
  const [pasted, setIsPasted] = useState(false);
  const [messagesContainer, setMessagesContainer] = useState([]);

  const getLineError = useCallback(
    (text, index, all) => {
      // if too many lines
      if (index >= 50) {
        return "Only 50 Variable Types allowed.";
      }

      if (text.length < 3) {
        return `Enter at least three characters.`;
      }

      if (text.length > 20) {
        return `Don't exceed more than twenty characters.`;
      }

      if (!text.match(/^[a-zA-Z0-9_ ]+$/)) {
        return `No special characters (but spaces) allowed.`;
      }

      // check if this line is the same as any of the previous
      const duplicateOf = all.slice(0, index).findIndex((v) => v === text);
      if (duplicateOf !== -1) {
        return `Duplicate of line ${duplicateOf + 1}`;
      }

      return "";
    },
    []
  );

  useEffect(() => {
    const lineTexts = variableTypeName.split("\n");
    setMessagesContainer(lineTexts.map(getLineError));
  }, [variableTypeName, getLineError, setMessagesContainer]);

  const handlePaster = (e) => {
    e.persist();

    setIsPasted(true);
    setClipboardData(e.clipboardData.getData("text"));
  };

  const handleChange = (e) => {
    e.persist();
    var { keyCode } = e;
    var { value } = e.target;

    if (keyCode === 13) {
      setVariableTypeName(`${value}\n`);
      return;
    } else if (pasted === true && keyCode === 13) {
      setVariableTypeName(`${variableTypeName.concat(clipboardData)}\n`);
      setIsPasted(false);
      return;
    } else if (pasted === true && keyCode !== 13) {
      setVariableTypeName(`${variableTypeName.concat(clipboardData)}`);
      setIsPasted(false);
      return;
    } else {
      setVariableTypeName(`${value}`);
      return;
    }
  };

  return (
    <div>
      <textarea
        placeholder="Variable Types"
        maxLength={100}
        value={variableTypeName}
        onPaste={(e) => handlePaster(e)}
        onChange={(e) => handleChange(e)}
      />

      {messagesContainer.map((message, i, arr) => {
        console.log("message ", message);
        return message ? (
          <p key={i} className="Messages">{`Error on line ${
            i + 1
          }: ${message}`}</p>
        ) : null;
      })}
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <TextArea onSave={console.log} />
    </div>
  );
}