Javascript 如何使用react-useContext在同一组件中显示上下文中的数据

Javascript 如何使用react-useContext在同一组件中显示上下文中的数据,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我正在创建一个react向导组件,并希望使用上下文在父级和子级之间传递数据 因此,我创建了一个向导、上下文、提供程序和自定义挂钩,但问题是,如果我尝试在向导组件上使用上下文,它不会显示正确的信息 (见附件) 如何使其能够依赖于向导本身上下文中的数据,以便将登录名传输到自定义挂钩 useWizard.js: import React, { useContext, useEffect } from "react"; import { WizardContext } from "./WizardCon

我正在创建一个react向导组件,并希望使用上下文在父级和子级之间传递数据

因此,我创建了一个向导、上下文、提供程序和自定义挂钩,但问题是,如果我尝试在向导组件上使用上下文,它不会显示正确的信息

(见附件)

如何使其能够依赖于向导本身上下文中的数据,以便将登录名传输到自定义挂钩

useWizard.js:

import React, { useContext, useEffect } from "react";
import { WizardContext } from "./WizardContext";

const useWizard = () => {
  const [state, setState] = useContext(WizardContext);

  function setMaxSteps(maxSteps) {
    setState(state => ({ ...state, maxSteps }));
  }
  function moveToStep(index) {
    if (state.maxSteps && state.maxSteps > index) {
      setState({ ...state, currentStep: index });
      return index;
    }
    return state.currentStep;
  }

  function back() {
    if (state.maxSteps) {
      if (state.currentStep > 0) {
        setState({ ...state, currentStep: state.currentStep - 1 });
        window.scrollTo(0, 0);
      }
    }
  }

  //move back a step
  function next() {
    if (state.currentStep < state.maxSteps) {
      setState({ ...state, currentStep: state.currentStep + 1 });
      window.scrollTo(0, 0);
    }
  }

  return {
    setMaxSteps,
    moveToStep,
    back,
    next,
    maxSteps: state.maxSteps,
    currentStep: state.currentStep,
    state
  };
};

export default useWizard;


上下文是从组件树上方最近的提供程序派生的。来自react文档

const value=useContext(MyContext)

接受上下文对象(从React.createContext返回的值)并返回该上下文的当前上下文值。当前上下文值由树中调用组件上方最近的值prop确定

在这种情况下,您有两个选项

1.您需要将应用程序(index.js)组件包装到提供商中

2.让向导组件作为提供程序,并尝试在子组件中使用useContext钩子

演示:


希望这有帮助

上下文来自组件树上方最近的提供者。来自react文档

const value=useContext(MyContext)

接受上下文对象(从React.createContext返回的值)并返回该上下文的当前上下文值。当前上下文值由树中调用组件上方最近的值prop确定

在这种情况下,您有两个选项

1.您需要将应用程序(index.js)组件包装到提供商中

2.让向导组件作为提供程序,并尝试在子组件中使用useContext钩子

演示:


希望这有助于您在
上下文相同的级别调用
useContext
。提供程序

function Wizard(props) {
  // useWizard calls useContext
  const { state, currentStep, back, next, maxSteps, setMaxSteps } = useWizard();

  return (
    <div className="wizard">
      <WizardProvider
        maxSteps={React.Children.count(props.children)}
        currentStep={0}
      >
        <div className="wizard__content">
          {`in wizard: cur=${currentStep}, max=${maxSteps}`}
        </div>
      </WizardProvider>
    </div>
  );
}

请参阅,.

您调用的
useContext
上下文提供程序处于相同级别

function Wizard(props) {
  // useWizard calls useContext
  const { state, currentStep, back, next, maxSteps, setMaxSteps } = useWizard();

  return (
    <div className="wizard">
      <WizardProvider
        maxSteps={React.Children.count(props.children)}
        currentStep={0}
      >
        <div className="wizard__content">
          {`in wizard: cur=${currentStep}, max=${maxSteps}`}
        </div>
      </WizardProvider>
    </div>
  );
}

请参阅。

多亏了这篇文章,我找到了解决方案: 所述解决方案是在向导文件上创建一个reducer,这样向导就可以访问其数据以及子文件:

Wizard.jsx

import React, {
  useState,
  useEffect,
  useLayoutEffect,
  useContext,
  useReducer
} from "react";
import PropTypes from "prop-types";
import "./wizard.scss";

import {
  WizardContext,
  wizardReducer,
  SET_CURRENT_STEP,
  SET_MAX_STEPS,
  BACK,
  NEXT
} from "./WizardContext";

function StepContent(props) {
  const { selected, children, ...other } = props;

  return (
    <li {...other} selected={selected}>
      {children}
    </li>
  );
}

function Wizard(props) {
  const { onClose, onChange, pageContentClassName } = props;

  function onClick(index) {
    dispatch({ type: SET_CURRENT_STEP, currentStep: index });
    // setSelected(index);
  }

  //get the progressBar steps
  const steps = React.Children.map(props.children, page => {
    const { id, label, description } = page.props;
    return <div id={id} label={label} description={description} />;
  });

  function getContentAt(index) {
    return stepContentWithProps[index];
  }

  const stepsWithProps = React.Children.map(props.children, (step, index) => {
    const newStep = React.cloneElement(step, {});
    return newStep;
  });

  const stepContentWithProps = stepsWithProps.map((step, index) => {
    const { children } = step.props;

    return (
      <StepContent key={index} className={pageContentClassName}>
        {children}
      </StepContent>
    );
  });

  const initialState = {
    maxSteps: React.Children.count(props.children),
    currentStep: 0
  };
  const [wizardData, dispatch] = useReducer(wizardReducer, initialState);

  return (
    <div className="wizard">
      <p>This text is in wizard: currentStep={wizardData.currentStep}</p>
      <WizardContext.Provider value={{ wizardData, dispatch }}>
        <div className="wizard__upper">
          <ul currentIndex={wizardData.currentStep} onChange={onClick}>
            {steps}
          </ul>
        </div>
        <div className="wizard__separator" />
        <div className="wizard__content">{stepsWithProps}</div>
        <div>
          <button onClick={() => dispatch({ type: BACK })}>Back</button>
          <button onClick={() => dispatch({ type: NEXT })}>Next</button>
        </div>
      </WizardContext.Provider>
    </div>
  );
}

Wizard.propTypes = {
  /**
   * Specify the text to be read by screen-readers when visiting the <Tabs>
   * component
   */
  ariaLabel: PropTypes.string,

  /**
   * Pass in a collection of <Tab> children to be rendered depending on the
   * currently selected tab
   */
  children: PropTypes.node,

  /**
   * Provide a className that is applied to the <PageContent> components
   */
  pageContentClassName: PropTypes.string
};

export default Wizard;

Index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";
import Wizard from "./Wizard";
import Cmp2 from "./Cmp2";

function App() {
  const [wizardVisible, setWizardVisible] = useState(false);
  return (
    <div className="App">
      <h1>
        Wizard: why cant I see currentStep in wizard
        <br />
        (WORKING NOW!!!)
      </h1>
      <Wizard>
        <div label="ddd">This is step1</div>
        <Cmp2 />
        <div label="ddd">This is step3</div>
      </Wizard>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
import React,{useState}来自“React”;
从“react dom”导入react dom;
导入“/styles.css”;
从“/Wizard”导入向导;
从“/Cmp2”导入Cmp2;
函数App(){
const[wizardVisible,setWizardVisible]=useState(false);
返回(
向导:为什么在向导中看不到当前步骤

(正在工作!!!) 这是第一步 这是第三步 ); } const rootElement=document.getElementById(“根”);
ReactDOM.render(

多亏了这篇文章,我找到了解决方案: 所述解决方案是在向导文件上创建一个reducer,这样向导就可以访问其数据以及子文件:

Wizard.jsx

import React, {
  useState,
  useEffect,
  useLayoutEffect,
  useContext,
  useReducer
} from "react";
import PropTypes from "prop-types";
import "./wizard.scss";

import {
  WizardContext,
  wizardReducer,
  SET_CURRENT_STEP,
  SET_MAX_STEPS,
  BACK,
  NEXT
} from "./WizardContext";

function StepContent(props) {
  const { selected, children, ...other } = props;

  return (
    <li {...other} selected={selected}>
      {children}
    </li>
  );
}

function Wizard(props) {
  const { onClose, onChange, pageContentClassName } = props;

  function onClick(index) {
    dispatch({ type: SET_CURRENT_STEP, currentStep: index });
    // setSelected(index);
  }

  //get the progressBar steps
  const steps = React.Children.map(props.children, page => {
    const { id, label, description } = page.props;
    return <div id={id} label={label} description={description} />;
  });

  function getContentAt(index) {
    return stepContentWithProps[index];
  }

  const stepsWithProps = React.Children.map(props.children, (step, index) => {
    const newStep = React.cloneElement(step, {});
    return newStep;
  });

  const stepContentWithProps = stepsWithProps.map((step, index) => {
    const { children } = step.props;

    return (
      <StepContent key={index} className={pageContentClassName}>
        {children}
      </StepContent>
    );
  });

  const initialState = {
    maxSteps: React.Children.count(props.children),
    currentStep: 0
  };
  const [wizardData, dispatch] = useReducer(wizardReducer, initialState);

  return (
    <div className="wizard">
      <p>This text is in wizard: currentStep={wizardData.currentStep}</p>
      <WizardContext.Provider value={{ wizardData, dispatch }}>
        <div className="wizard__upper">
          <ul currentIndex={wizardData.currentStep} onChange={onClick}>
            {steps}
          </ul>
        </div>
        <div className="wizard__separator" />
        <div className="wizard__content">{stepsWithProps}</div>
        <div>
          <button onClick={() => dispatch({ type: BACK })}>Back</button>
          <button onClick={() => dispatch({ type: NEXT })}>Next</button>
        </div>
      </WizardContext.Provider>
    </div>
  );
}

Wizard.propTypes = {
  /**
   * Specify the text to be read by screen-readers when visiting the <Tabs>
   * component
   */
  ariaLabel: PropTypes.string,

  /**
   * Pass in a collection of <Tab> children to be rendered depending on the
   * currently selected tab
   */
  children: PropTypes.node,

  /**
   * Provide a className that is applied to the <PageContent> components
   */
  pageContentClassName: PropTypes.string
};

export default Wizard;

Index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";
import Wizard from "./Wizard";
import Cmp2 from "./Cmp2";

function App() {
  const [wizardVisible, setWizardVisible] = useState(false);
  return (
    <div className="App">
      <h1>
        Wizard: why cant I see currentStep in wizard
        <br />
        (WORKING NOW!!!)
      </h1>
      <Wizard>
        <div label="ddd">This is step1</div>
        <Cmp2 />
        <div label="ddd">This is step3</div>
      </Wizard>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
import React,{useState}来自“React”;
从“react dom”导入react dom;
导入“/styles.css”;
从“/Wizard”导入向导;
从“/Cmp2”导入Cmp2;
函数App(){
const[wizardVisible,setWizardVisible]=useState(false);
返回(
向导:为什么在向导中看不到当前步骤

(正在工作!!!) 这是第一步 这是第三步 ); } const rootElement=document.getElementById(“根”);
ReactDOM.render(

我认为由于我们不能在与Provider相同的组件中使用useContext(),我认为我们可以做一些变通,我认为这将有助于在页面/屏幕等主要组件中使用

 // This will be your child component  
 function Wizard(props) {
  // useWizard calls useContext
  const { state, currentStep, back, next, maxSteps, setMaxSteps } = useWizard();

  return (
    <div className="wizard">
        <div className="wizard__content">
          {`in wizard: cur=${currentStep}, max=${maxSteps}`}
        </div>
    </div>
  );
}

// This is your main Page
export default function WizardPage(){
  return <WizardProvider 
          maxSteps={React.Children.count(props.children)}
          currentStep={0}>
            <Wizard /> 
   </WizardProvider>
}
//这将是您的子组件
功能向导(道具){
//useWizard调用useContext
const{state,currentStep,back,next,maxSteps,setMaxSteps}=useWizard();
返回(
{`在向导中:cur=${currentStep},max=${maxSteps}`}
);
}
//这是你的主页
导出默认函数向导页(){
返回
}

我认为,由于我们不能在与提供者相同的组件中使用useContext(),我认为我们可以做一些变通,我认为这将有助于在页面/屏幕等主要组件中使用

 // This will be your child component  
 function Wizard(props) {
  // useWizard calls useContext
  const { state, currentStep, back, next, maxSteps, setMaxSteps } = useWizard();

  return (
    <div className="wizard">
        <div className="wizard__content">
          {`in wizard: cur=${currentStep}, max=${maxSteps}`}
        </div>
    </div>
  );
}

// This is your main Page
export default function WizardPage(){
  return <WizardProvider 
          maxSteps={React.Children.count(props.children)}
          currentStep={0}>
            <Wizard /> 
   </WizardProvider>
}
//这将是您的子组件
功能向导(道具){
//useWizard调用useContext
const{state,currentStep,back,next,maxSteps,setMaxSteps}=useWizard();
返回(
{`在向导中:cur=${currentStep},max=${maxSteps}`}
);
}
//这是你的主页
导出默认函数向导页(){
返回
}

你能看一下吗?我在读了那篇文章后得出了我的问题,所以这不是我要找的。问题是我有为向导组件创建的上下文,所以我想在向导层次结构中使用它,(如果我把组件放在它调用的地方(比如当前在app.js中),这意味着向导会对其进行解析,因此在显示时会使用它),谢谢。您能看一下吗。我在阅读了那篇文章后得出了我的问题,因此这不是我要查找的内容。问题是我有为向导组件创建的上下文,因此希望在向导层次结构中使用它,(如果我把组件放在它调用的地方(比如现在的app.js),这意味着向导会解析它,因此在显示时会使用它),谢谢。我正在尝试创建一个向导组件,所以在提供程序中包装它的父组件(应该在app.js的向导下游配置),不是很好,而且我在app.js中添加了代码,因为它正在向导中解析,我想看看它如何/是否可以工作。所以这并不能解决我的问题(这并不是说这是错误的答案),谢谢。您的向导组件正在使用上下文消费者ie useWizard custo
import React, { useState, useContext, useEffect } from "react";
import { WizardContext, SET_CURRENT_STEP } from "./WizardContext";

function Cmp2(props) {
  const { wizardData, dispatch } = useContext(WizardContext);

  return (
    <div>
      <br />
      <p>This is Step 2</p>
      {`in step2 (inner child of wizard): cur=${wizardData.currentStep}`}
      <br />
      <button
        onClick={() => dispatch({ type: SET_CURRENT_STEP, currentStep: 1 })}
      >
        Click me to change current step
      </button>
      <br />
      <br />
    </div>
  );
}

export default Cmp2;
 // This will be your child component  
 function Wizard(props) {
  // useWizard calls useContext
  const { state, currentStep, back, next, maxSteps, setMaxSteps } = useWizard();

  return (
    <div className="wizard">
        <div className="wizard__content">
          {`in wizard: cur=${currentStep}, max=${maxSteps}`}
        </div>
    </div>
  );
}

// This is your main Page
export default function WizardPage(){
  return <WizardProvider 
          maxSteps={React.Children.count(props.children)}
          currentStep={0}>
            <Wizard /> 
   </WizardProvider>
}