使用React、React Router和React Relay,我应该使用哪个来存储和检索状态?

huangapple go评论73阅读模式
英文:

Using React, React Router, and React Relay which should I use to store and retrieve state?

问题

我目前正在使用React与React Router以及React Relay。这些都有更新/传递数据的方法。React使用useState,React Router使用其pushState包装器(location.state),Relay使用其updater()方法。

但我不确定应该使用哪个来处理全局状态(如果有的话)。我的应用的所有页面都需要一个特定的ID,这不是一个会话ID。想象一个具有5个步骤的表单。第1步没有ID,第2步在成功提交后获取ID,现在在第3-5步中,它需要将该ID呈现为隐藏输入(以示例)。让我们称之为formId

目前,我正在使用React Router的location.state来传递它,但感觉不对。相反,我觉得我应该有一种方法在设置了formId后获取它。如果formId为null,则将它们发送到第1步,如果不为null,则让当前页面/路由加载。

当然,我可以使用window.formId,但那似乎是最不合适的方法。

英文:

I'm currently using React with React Router and React Relay. Each of these has ways of updating/passing data. React with useState, React Router with it's pushState wrapper (location.state), and Relay with it's updater() method.

I'm unsure however which I should be using to handle a global state (if any at all). There is a particular ID that all pages of my app need that is not a session. Imagine a form with let's say 5 steps. Step 1 has no ID, Step 2 gets the ID on successful submit, and now on steps 3-5 it needs that ID to be rendered into a hidden input (as an example). Let's call it formId.

Currently, I'm passing it using React Router with location.state but it feels wrong. Instead I feel like I should have a way to get this formId once it's set. If formId is null send them to Step 1 and if it's not null let the current page/route load.

Of course, I could use window.formId but that seems to most wrong.

答案1

得分: 1

我使用了React的Context API。它看起来像这样:

// FormIdContext.tsx
import React, { createContext, useState, useContext } from 'react';

interface FormIdContextType {
  formId: string | null;
  setFormId: (formId: string | null) => void;
}

const FormIdContext = createContext<FormIdContextType | undefined>(undefined);

// 用于消费FormIdContext的自定义钩子
export function useFormIdContext(): FormIdContextType {
  const context = useContext(FormIdContext);
  if (!context) {
    throw new Error('useFormIdContext必须在FormIdContext.Provider内部使用');
  }
  return context;
}

export function FormIdProvider(props: React.PropsWithChildren<{}>) {
  const [formId, setFormId] = useState<string | null>(null);

  return (
    <FormIdContext.Provider value={{ formId, setFormId }}>
      {props.children}
    </FormIdContext.Provider>
  );
}

然后在我的路由器中:

// App.tsx
import React, { useState } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Step1 from './Step1';
import Step2 from './Step2';
import Step3 from './Step3';
import FormIdContext from './FormIdContext';

function App() {
  const [formId, setFormId] = useState<string | null>(null);

  return (
    <Router>
      <FormIdContext.Provider value={{ formId, setFormId }}>
        <Route path="/step1" component={Step1} />
        <Route path="/step2" component={Step2} />
        <Route path="/step3" component={Step3} />
      </FormIdContext.Provider>
    </Router>
  );
}

export default App;

然后我可以像这样获取和设置这些值:

// Step3.tsx
import React from 'react';
import { useHistory } from 'react-router-dom';
import { useFormIdContext } from './FormIdContext';

function Step3() {
  const history = useHistory();
  const { formId, setFormId } = useFormIdContext();

  const handleFormSubmission = () => {
    // 假设你有表单数据并且想执行一些提交逻辑
    // 一旦提交成功并且你获取了formId,你可以更新状态
    const newFormId = 'new_generated_form_id';
    setFormId(newFormId);

    // 可选地,你可以导航到另一页或执行其他操作
    // 在这里,我们只是回到Step2作为示例
    history.push('/step2');
  };

  return (
    <div>
      {/* 可能使用formId的第3步内容 */}
      <h1>第3步</h1>
      <p>当前formId{formId}</p>
      <button onClick={handleFormSubmission}>提交表单</button>
    </div>
  );
}

export default Step3;

希望这些帮助!

英文:

I ended up using React's Context API.

It looked something like this

// FormIdContext.tsx
import React, { createContext, useState, useContext } from &#39;react&#39;;

interface FormIdContextType {
  formId: string | null;
  setFormId: (formId: string | null) =&gt; void;
}

const FormIdContext = createContext&lt;FormIdContextType | undefined&gt;(undefined);

// A custom hook to consume the FormIdContext
export function useFormIdContext(): FormIdContextType {
  const context = useContext(FormIdContext);
  if (!context) {
    throw new Error(&#39;useFormIdContext must be used within a FormIdContext.Provider&#39;);
  }
  return context;
}

export function FormIdProvider(props: React.PropsWithChildren&lt;{}&gt;) {
  const [formId, setFormId] = useState&lt;string | null&gt;(null);

  return (
    &lt;FormIdContext.Provider value={{ formId, setFormId }}&gt;
      {props.children}
    &lt;/FormIdContext.Provider&gt;
  );
}

Then in my router

// App.tsx
import React, { useState } from &#39;react&#39;;
import { BrowserRouter as Router, Route } from &#39;react-router-dom&#39;;
import Step1 from &#39;./Step1&#39;;
import Step2 from &#39;./Step2&#39;;
import Step3 from &#39;./Step3&#39;;
import FormIdContext from &#39;./FormIdContext&#39;;

function App() {
  const [formId, setFormId] = useState&lt;string | null&gt;(null);

  return (
    &lt;Router&gt;
      &lt;FormIdContext.Provider value={{ formId, setFormId }}&gt;
        &lt;Route path=&quot;/step1&quot; component={Step1} /&gt;
        &lt;Route path=&quot;/step2&quot; component={Step2} /&gt;
        &lt;Route path=&quot;/step3&quot; component={Step3} /&gt;
      &lt;/FormIdContext.Provider&gt;
    &lt;/Router&gt;
  );
}

export default App;

Then I can get and set those values like this

// Step3.tsx
import React from &#39;react&#39;;
import { useHistory } from &#39;react-router-dom&#39;;
import { useFormIdContext } from &#39;./FormIdContext&#39;;

function Step3() {
  const history = useHistory();
  const { formId, setFormId } = useFormIdContext();

  const handleFormSubmission = () =&gt; {
    // Assuming you have the form data and you want to perform some submission logic
    // Once the submission is successful and you get the formId, you can update the state
    const newFormId = &#39;new_generated_form_id&#39;;
    setFormId(newFormId);

    // Optionally, you can navigate to another page or perform other actions
    // Here, we simply go back to Step2 as an example
    history.push(&#39;/step2&#39;);
  };

  return (
    &lt;div&gt;
      {/* Your Step 3 content that may use formId */}
      &lt;h1&gt;Step 3&lt;/h1&gt;
      &lt;p&gt;Current formId: {formId}&lt;/p&gt;
      &lt;button onClick={handleFormSubmission}&gt;Submit Form&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default Step3;

huangapple
  • 本文由 发表于 2023年7月28日 01:32:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76782189.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定