如何使用用户输入获取Reaction函数来更新状态

1u4esq0p  于 2022-10-15  发布在  React
关注(0)|答案(1)|浏览(173)

我在Reaction中编写了一个函数,该函数通过呈现的提交表单接受用户的输入,使用它来查询API并更新表单中的p标记内容。这是以下代码:

var textfield = ""
function Form (){
        const [ name, getNFT ] = useState("")
        let postName = (e) =>{
            let output
            async function getInfo(e) {
                e.preventDefault()
                try {
                    const resp = await axios.post("/hey_honey", {
                        name
                    })
                    console.log(resp.data)
                    output = resp.data
                    return output
                } catch (error) {
                    console.error(error)
                }
            }

        getInfo(e).then(output =>{console.log("output is outside of function scope", output)
        })
        textfield = output
        return textfield 
    }

    return (
        <div className="App">
            <form onSubmit={postName}>
                <input type="text" value={name} onChange={(e) => getNFT(e.target.value)}/>
                <button type="submit" >Get Collection's Gallery</button>
                <p>{textfield}</p>
            </form>
        </div>
    )
}

我已经成功地获得了我想要的JSON字符串。问题是,我似乎无法更新呈现的表单,因为它不在postName的函数作用域之外,或者由postName修改的任何内容,即使在表单之外示例化,实际上也无法更改状态。
我一度认为这很可能是因为这是使用类的一个更合适的示例,但是我不能使用useState,因此无法存储在提交表单中写出的内容。(**编辑:**经过一些研究后,我可以使用类来完成这项工作。从技术上讲,我不需要将useState用于表单,而是可以使用setState并简单地将setState示例化为空字符串。它看起来如下所示,为了方便起见,我们只有一个函数,它只返回输入,而不是异步函数:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: '', textfield: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    this.setState({textfield: event.target.value})
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
        <p>{this.state.textfield}</p>
      </form>

    );
  }
}

然而,我们仍然遇到更新表单本身的问题。)

编辑这是表单元素的特定问题吗?当有人在博客上发表评论时,有没有我应该使用的完全不同的组件?我之所以被表单所吸引,是因为它们接受用户输入,然后给您提供一些您可以操作的东西,但一旦您设置它们,它们是否就是不可变的?

在撰写本文时,我开始考虑现在应该导出一个存储值,在我的例子中是Textfield,然后将其传递到一个全新的组件中。将会更新。

eqqqjvef

eqqqjvef1#

问题是,我似乎无法更新呈现的表单,因为它不在postName的函数作用域之外,或者由postName修改的任何内容,即使在表单之外示例化,实际上也无法更改状态。
说到React,在一天结束的时候,如果你想让它重新呈现,你需要更新React状态。您在这里使用textfield所做的是更新一个JS变量,但Reaction无法知道该变量是否不同,因此它不知道要重新呈现。
注意你在用你的input做什么。因为您已经设置了value,所以它是一个“受控输入”,因此您可以看到您输入的文本的唯一原因是因为您正在更新React状态,并在每次按键时触发重新呈现。
您可以对网络请求的结果执行相同的操作。一旦请求完成,您可以更新一段状态,这将触发重新呈现。请注意,如果您不使用该状态(例如,通过呈现其中的一部分),您将无法仅通过浏览器查看它来判断Reaction已经重新呈现。
下面是一个稍有不同的示例,它根据表单输入发出网络请求并呈现结果。(对于这个API来说,变量名没有多大意义,只是想保持较小的差异)。

function Form() {
  const [name, getNFT] = useState("");
  const [jokes, setJokes] = useState([]);

  let postName = (e) => {
    let output;
    async function getInfo(e) {
      e.preventDefault();
      try {
        // swapped this out so we could see a result
        const resp = await axios.get(`https://icanhazdadjoke.com/search?term=${name}`, {
          headers: {
            // you need to tell this API you want the results as JSON, instead of HTML (the default)
            'Accept': 'application/json'
          }
        });
        console.log(resp.data);
        output = resp.data;
        return output;
      } catch (error) {
        console.error(error);
      }
    }

    getInfo(e).then((output) => {
      console.log("output is outside of function scope", output);

      // this is the big change!
      setJokes(output.results);
    });
  };

  return (
    <div className="App">
      <form onSubmit={postName}>
        <input
          type="text"
          value={name}
          onChange={(e) => getNFT(e.target.value)}
        />
        <button type="submit">Get Collection's Gallery</button>
        <p>{jokes[0]?.joke}</p>
      </form>
    </div>
  );
}

这里有一个版本,它做了同样的事情,但稍微清理了一下,只是为了进行比较:

// this is a pure js function - no react! It just makes the request and returns the result
async function searchJokes(jokeTerm) {
  try {
    // swapped this out so we could see a result
    const jokesResponse = await axios.get(
      `https://icanhazdadjoke.com/search?term=${jokeTerm}`,
      {
        headers: {
          // you need to tell this API you want the results as JSON, instead of HTML (the default)
          Accept: "application/json"
        }
      }
    );

    console.log("jokes response", jokesResponse);
    return jokesResponse.data;
  } catch (error) {
    console.error(error);
  }
}

function Form() {
  const [searchTerm, setSearchTerm] = useState("");
  const [jokes, setJokes] = useState([]);

  return (
    <div className="App">
      <form
        onSubmit={async (e) => {
          e.preventDefault();

          // whereas the pure js function can just return its request normally, inside here we need
          // to take the result and stick it in React state.
          const jokesData = await searchJokes(searchTerm);
          setJokes(jokesData.results);
        }}
      >
        <input
          type="text"
          value={searchTerm}
          onChange={(e) => setSearchTerm(e.target.value)}
        />
        <button type="submit">Search Jokes</button>
        <p>{jokes[0]?.joke}</p>
      </form>
    </div>
  );
}

(Sandbox)。需要说明的是,以上几点绝对不是完美的!

getInfo(e).then(output =>{console.log("output is outside of function scope", output)
        })
        textfield = output
        return textfield

撇开REACT不谈,要记住的一件事是,then内的函数内的代码将在getInfo(e)完成从Internet获取其信息时运行,但之后的行立即运行而不等待,因为getInfo调用返回Promise。在JS中,这样的异步逻辑是非阻塞的!您可以在上面看到如何使用await来避免需要then和嵌套。(但是,值得记住的是,async/await只是承诺和.then的花哨语法,所以可以用其中一个做的任何事情都可以用另一个做。)
此外,由于函数作用域的限制,您将无法在then函数之外访问output。您必须在该函数内部进行变量赋值,或者使用Async AWait将事情变得稍微平坦一些。
我一度认为这很可能是因为这是使用类的一个更合适的示例,但是我不能使用useState,因此无法存储在提交表单中写出的内容。我错过了什么吗?
在Reaction中,过去需要为更复杂的组件(如具有状态的组件)使用类,并且只能使用表示组件的函数。但是自从它们引入钩子以来,类组件和功能组件可以以不同的方式做相同的事情,所以您在这里所做的一切都很好!我会坚持使用功能组件,就像你在学习的时候所拥有的那样。
在React之外,在处理状态时,类是一个很好的选择(尽管您也可以用嵌套函数做相同的事情)。但是您仍然需要一些方法来将对您的普通JS类状态的更新Map到React状态。首先,我主要关注在Reaction中存储状态,当您构建更大的应用程序时,您可以花一些时间学习如何将它们绑定到您自己的定制类中,或者引入一个状态管理库(Redux可能是最著名的)来为您处理这一问题。

相关问题