在另一个组件中访问组件状态

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

Access a component state in another component

问题

我有一个名为collection的状态的子组件(CollectionsBar.jsx)。当点击一个div时,它会更新该状态。
我想在父组件(Products.jsx)中访问该状态。所以当状态被点击时,它会改变span标签。

子组件:

import React, { useEffect, useState } from "react";
import useFetch from "../../hooks/useFetch";
import "./CollectionsBar.scss";

const CollectionsBar = () => {
  
  // 设置 useFetch 的数据
  const { data, loading, error } = useFetch(
    "/collection-list?populate[0]=collecao&populate=FundoTitulo&populate[1]=collecao.Imagem&populate=collecao.products&populate=collecao.products.img&populate=collecao.products.img2"
  );
  const minifyData = data?.attributes.collecao.data;
  const [collection, setCollection] = useState();

  // CollectionsBar 组件
  return (
    <div className="sl-c-collections-bar">
      <div className="sl-l-bar__flex">
        {minifyData?.map((item, index) => {
          return (
            <div
              onClick={() => {
                setCollection(index);
              }}
              key={index}
              className="sl-c-flex__box"
            >
              <img
                src={
                  import.meta.env.VITE_REACT_APP_UPLOADS_URL +
                  item.attributes.Imagem.data.attributes.url
                }
                alt="Imagem Produto"
              />
            </div>
          );
        })}
      </div>
    </div>
  );
};

export default CollectionsBar;

父组件:

import React, { useEffect } from "react";
import useFetch from "../../hooks/useFetch";
import CollectionsBar from "../../components/CollectionsBar/CollectionsBar";
import "./Products.scss";
const Products = () => {
  return (
    <div className="sl-c-products">
      <div className="sl-l-products__flex">
        <span></span>
      </div>
      <CollectionsBar />
    </div>
  );
};

export default Products;

我只想知道最佳的实现方式...

英文:

I have a children component (CollectionsBar.jsx) with a state named collection. When a div gets clicked, it updates the state.
I want to access the state in the parent's component (Products.jsx). So when the state gets clicked, it changes the span tag.

Children Component:

import React, { useEffect, useState } from &quot;react&quot;;
import useFetch from &quot;../../hooks/useFetch&quot;;
import &quot;./CollectionsBar.scss&quot;;

const CollectionsBar = () =&gt; {
  
  //SETTING DATA FOR useFetch
  const { data, loading, error } = useFetch(
    &quot;/collection-list?populate[0]=collecao&amp;populate=FundoTitulo&amp;populate[1]=collecao.Imagem&amp;populate=collecao.products&amp;populate=collecao.products.img&amp;populate=collecao.products.img2&quot;
  );
  const minifyData = data?.attributes.collecao.data;
  const [collection, setCollection] = useState();

  //COLLECTIONS BAR COMPONENT
  return (
    &lt;div className=&quot;sl-c-collections-bar&quot;&gt;
      &lt;div className=&quot;sl-l-bar__flex&quot;&gt;
        {minifyData?.map((item, index) =&gt; {
          return (
            &lt;div
              onClick={() =&gt; {
                setCollection(index);
              }}
              key={index}
              className=&quot;sl-c-flex__box&quot;
            &gt;
              &lt;img
                src={
                  import.meta.env.VITE_REACT_APP_UPLOADS_URL +
                  item.attributes.Imagem.data.attributes.url
                }
                alt=&quot;Imagem Produto&quot;
              /&gt;
            &lt;/div&gt;
          );
        })}
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default CollectionsBar;

Parent Component:

import React, { useEffect } from &quot;react&quot;;
import useFetch from &quot;../../hooks/useFetch&quot;;
import CollectionsBar from &quot;../../components/CollectionsBar/CollectionsBar&quot;;
import &quot;./Products.scss&quot;;
const Products = () =&gt; {
  return (
    &lt;div className=&quot;sl-c-products&quot;&gt;
      &lt;div className=&quot;sl-l-products__flex&quot;&gt;
        &lt;span&gt;&lt;/span&gt;
      &lt;/div&gt;
      &lt;CollectionsBar /&gt;
    &lt;/div&gt;
  );
};

export default Products;

I just want to know the best way of doing it...

答案1

得分: 2

你有两个选项:

  1. 提升状态。

    这是更简单的方法。你只需要将状态移动到父组件,并将setter作为prop传递下来:

    const Products = () => {
      const [collection, setCollection] = useState();
      return (
        <div className="sl-c-products">
          <div className="sl-l-products__flex">
            <span></span>
          </div>
          <CollectionsBar setCollection={setCollection} />
        </div>
      );
    };
    
    export default Products;
    

    然后在子组件中可以使用setter:

    const CollectionsBar = ({ setCollection }) => {
      const { data, loading, error } = useFetch("");
    
      return (
        <div className="sl-c-collections-bar">
          <div className="sl-l-bar__flex">
            {minifyData?.map((item, index) => {
              return (
                <div
                  onClick={() => {
                    setCollection(index);
                  }}
                  key={index}
                  className="sl-c-flex__box"
                >
                  <img
                    //...
                  />
                </div>
              );
            })}
          </div>
        </div>
      );
    };
    
    export default CollectionsBar;
    

    如果需要在子组件中使用该状态,也可以将状态作为prop传递。

  2. 使用useRef和forwardRef hooks。

    如果无法提升状态,你需要使用ref。对于这种情况,你需要对React的工作原理有一定的了解。

    按照相同的示例:

    创建一个ref(childStateRef),并将其作为prop传递给子组件。然后,使用ref可以调用在子组件中创建的函数。

    const Products = () => {
      const childStateRef = useRef(null);
      console.log(childState.current.getCollection()); // 这将记录状态
      return (
        <div className="sl-c-products">
          <div className="sl-l-products__flex">
            <span></span>
          </div>
          <CollectionsBar ref={childStateRef} />
        </div>
      );
    };
    

    在子组件中:

    使用forwardRef包装组件,并使用"useImperativeHandle"创建一个函数来获取状态。

    const CollectionsBar = forwardRef((props, _ref) => {
      const { data, loading, error } = useFetch("");
      const [collection, setCollection] = useState();
      useImperativeHandle(_ref, () => ({
        getCollection: () => {
          return collection;
        },
      }));
      return (
        <div className="sl-c-collections-bar">
          <div className="sl-l-bar__flex">
            {minifyData?.map((item, index) => {
              return (
                <div
                  onClick={() => {
                    setCollection(index);
                  }}
                  key={index}
                  className="sl-c-flex__box"
                >
                  <img
                    //...
                  />
                </div>
              );
            })}
          </div>
        </div>
      );
    });
    
    export default CollectionsBar;
    
英文:

You have two options:

  1. Lifting up the state.

    This is the simpler way to do it. You just need to move your state to the parent component, and pass the setter down as a prop:

    const Products = () =&gt; {
    const [collection, setCollection] = useState();
      return (
        &lt;div className=&quot;sl-c-products&quot;&gt;
          &lt;div className=&quot;sl-l-products__flex&quot;&gt;
            &lt;span&gt;&lt;/span&gt;
          &lt;/div&gt;
          &lt;CollectionsBar setCollection={setCollection} /&gt;
        &lt;/div&gt;
      );
    };
    

    export default Products;

Then in the children you can use the setter:

const CollectionsBar = ({setCollection}) =&gt; {
  const { data, loading, error } = useFetch(&quot;&quot;);

  return (
    &lt;div className=&quot;sl-c-collections-bar&quot;&gt;
      &lt;div className=&quot;sl-l-bar__flex&quot;&gt;
        {minifyData?.map((item, index) =&gt; {
          return (
            &lt;div
              onClick={() =&gt; {
                setCollection(index);
              }}
              key={index}
              className=&quot;sl-c-flex__box&quot;
            &gt;
              &lt;img
                //...
              /&gt;
            &lt;/div&gt;
          );
        })}
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default CollectionsBar;

You also can pass the state if you need to use it in the children component.

  1. Use the useRef and forwardRef hooks

If by any chance, you can't lift up the state, you need to use ref. For this alternative, you should understand a bit more about how React works.

Following the same example:

Create a ref(childStateRef) and pass it as a prop to the children. Then, using the ref, you can call the fn you will create in the children comp.

const Products = () =&gt; {
const childStateRef = useRef&lt;any&gt;(null);
console.log(childState.current.getCollection()) //this will log the state
  return (
    &lt;div className=&quot;sl-c-products&quot;&gt;
      &lt;div className=&quot;sl-l-products__flex&quot;&gt;
        &lt;span&gt;&lt;/span&gt;
      &lt;/div&gt;
      &lt;CollectionsBar ref={childStateRef} /&gt;
    &lt;/div&gt;
  );
};

In your children component:

Wrap the component with forwardRef and use "useImperativeHandle" to create a function to get your state.

const CollectionsBar = forwardRef((props, _ref) =&gt; {
      const { data, loading, error } = useFetch(&quot;&quot;);
      const [collection, setCollection] = useState()
      useImperativeHandle(_ref, () =&gt; ({
        getCollection: () =&gt; {
        return collection;
        },
      }));
      return (
        &lt;div className=&quot;sl-c-collections-bar&quot;&gt;
          &lt;div className=&quot;sl-l-bar__flex&quot;&gt;
            {minifyData?.map((item, index) =&gt; {
              return (
                &lt;div
                  onClick={() =&gt; {
                    setCollection(index);
                  }}
                  key={index}
                  className=&quot;sl-c-flex__box&quot;
                &gt;
                  &lt;img
                    //...
                  /&gt;
                &lt;/div&gt;
              );
            })}
          &lt;/div&gt;
        &lt;/div&gt;
      );
    });
    
    export default CollectionsBar;

答案2

得分: 0

const [collection, setCollection] = useState(); 从子组件移动到父组件,然后将其作为 prop 传递下去。

// 父组件
...
const [collection, setCollection] = useState();
return (
  <CollectionsBar setCollection={setCollection}/>
)
....

// 子组件
const CollectionsBar = ({setCollection}) => {
  // 现在你的状态在父组件中,但可以从子组件中更改它
}
英文:

Move const [collection, setCollection] = useState(); from the child to the parent component and then pass it down as a prop.

// Parent component  
...  
const [collection, setCollection] = useState();  
 return (
   &lt;CollectionsBar setCollection={setCollection}/&gt; 
 )
....  

// Child component  
const CollectionsBar = ({setCollection}) =&gt; {  
 // now you have your state in a parent component but can change it from the child one  
}

huangapple
  • 本文由 发表于 2023年8月9日 02:38:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76862351.html
匿名

发表评论

匿名网友

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

确定