Reactjs 当道具数据使用react钩子更改时,我需要重新渲染,但我得到了无限的重新渲染

Reactjs 当道具数据使用react钩子更改时,我需要重新渲染,但我得到了无限的重新渲染,reactjs,react-hooks,Reactjs,React Hooks,对不起,我英语不好。。但我需要你们的帮助! 问题是当道具在EditField组件中更改时,我想重新播放 所以我试了两种方法 首先,我尝试使用useffect参数 在UseEffect钩子中,我尝试了UseEffect(()=>{},[facils]…就像这样 但当我尝试这种方式时,我得到了无限的重播 所以我尝试了另一种方法,我将GetDB函数传递给EditField组件,当我编辑道具数据时,我尝试调用GetDBfunction const useDbFacils = () => { c

对不起,我英语不好。。但我需要你们的帮助! 问题是当道具在EditField组件中更改时,我想重新播放

所以我试了两种方法

首先,我尝试使用useffect参数 在UseEffect钩子中,我尝试了UseEffect(()=>{},[facils]…就像这样 但当我尝试这种方式时,我得到了无限的重播

所以我尝试了另一种方法,我将GetDB函数传递给EditField组件,当我编辑道具数据时,我尝试调用GetDBfunction

const useDbFacils = () => {
  const [facils, setFacils] = useState([]);

  const fetchFacils = React.useCallback(() => {
    firebase
      .firestore()
      .collection("facils")
      .get()
      .then((snapshot) => {
        const newFacils = snapshot.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        }));
        setFacils(newFacils);
      });
  }, [setFacils]);
  useEffect(() => {
    fetchFacils();
  }, [fetchFacils]); // only you knows if this dependency is needed
  return [facils, fetchFacils];
};
但它没有达到我的预期

你能给我一些建议吗

const GetDB=()=>{
const[facils,setFacils]=useState([]);
useffect(()=>{
火基
.firestore()
.收集(“票据”)
.get()
。然后((快照)=>{
const newFacils=snapshot.docs.map((doc)=>({
id:doc.id,
…doc.data(),
}));
//防止firebase报价超过
控制台日志(!!!!FB警告!!!!”);
setFacils(新Facils);
});
}, []);
返回仪表板;
};
常量设施列表=()=>{
const facils=GetDB();
const[id,setId]=useState([]);
const[name,setName]=useState([]);
const[showEdit,setShowEdit]=useState(false);
...
...
返回(
身份证件
시설이름
{facils.length>0(
仪表图((项目)=>(
    EditItem(item.id,item.name)}> {item.id}-{item.name}
)) ) : ( 没有数据

)} {showEdit( setShowEdit(假)} handleChange={handleChange} refreshData={()=>GetDB} /> ) : ( )}
您不能从处理程序函数调用钩子。您可以做的是从
GetDB
hook实现并公开一个获取程序,然后调用它

另外,请确保在创建自定义挂钩时,在其名称前面加上
use
,因为它会告诉react在其上应用,并警告您使用不当

const useGetDB = () => {
  const [facils, setFacils] = useState([]);
  const fetchData = () => {
      firebase
      .firestore()
      .collection("facils")
      .get()
      .then((snapshot) => {
        const newFacils = snapshot.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        }));
        // prevent firebase quote exceed
        console.log("!!!!FB warniing!!!!");
        setFacils(newFacils);
      });
  }
  useEffect(() => {
    fetchData();
  }, []);
  return { facils, fetchData};
};
张贴你可以使用它如下

const FacilityLists = () => {
  const {facils, fetchData} = useGetDB();
  const [id, setId] = useState([]);
  const [name, setName] = useState([]);
  const [showEdit, setShowEdit] = useState(false);

...
...
return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-evenly" }}>
        <div>Id</div>
        <div>시설이름</div>
      </div>
      <div>
        {facils.length > 0 ? (
          facils.map((item) => (
            <ul key={item.id} onClick={() => EditItem(item.id, item.name)}>
              {item.id} - {item.name}
            </ul>
          ))
        ) : (
          <p>there is no data</p>
        )}
      </div>
      <div>
        {showEdit ? (
          <EditField
            id={id}
            name={name}
            showSave={() => setShowEdit(false)}
            handleChange={handleChange}
            refreshData={() => fetchData()}
          />
        ) : (
          <CreateField />
        )}
      </div>
    </div>
const FacilityLists=()=>{
const{facils,fetchData}=useGetDB();
const[id,setId]=useState([]);
const[name,setName]=useState([]);
const[showEdit,setShowEdit]=useState(false);
...
...
返回(
身份证件
시설이름
{facils.length>0(
仪表图((项目)=>(
    EditItem(item.id,item.name)}> {item.id}-{item.name}
)) ) : ( 没有数据

)} {showEdit( setShowEdit(假)} handleChange={handleChange} refreshData={()=>fetchData()} /> ) : ( )}
您需要使用“use”预设自定义钩子,否则react将不会将其识别为钩子,并将在每次渲染时创建一个新钩子,因为它不会被记忆


将其更改为useDB,它应该可以工作。

GetDB
重命名为
useFacils
。钩子的名称以
use
word开头,钩子(useffect)仅在函数组件或其他钩子中调用。不确定为什么在创建GetDB钩子时没有出现lint错误

从文档中:

它的名字应该总是以use开头,这样你一眼就能看出来 钩子的规则适用于它

而且:

我必须以“use”开头命名我的自定义钩子吗?请这样做。这个 习俗很重要。没有它,我们就无法做到 自动检查是否违反挂钩规则,因为我们 无法判断某个函数是否包含对 它

正如Shubham所指出的,这只是一个关于钩子名称的建议,为了让刷新工作,您还应该让自定义钩子返回fetch/refresh函数

const useDbFacils = () => {
  const [facils, setFacils] = useState([]);

  const fetchFacils = React.useCallback(() => {
    firebase
      .firestore()
      .collection("facils")
      .get()
      .then((snapshot) => {
        const newFacils = snapshot.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        }));
        setFacils(newFacils);
      });
  }, [setFacils]);
  useEffect(() => {
    fetchFacils();
  }, [fetchFacils]); // only you knows if this dependency is needed
  return [facils, fetchFacils];
};
在您的组件中:

function FacilsList() {
  const [facils, fetchFacils] = useDbFacils();

  // later
  {facils.length > 0 ? facils.map...
  // and
  <EditField
    id={id}
    name={name}
    showSave={() => setShowEdit(false)}
    handleChange={handleChange}
    refreshData={fetchFacils}
  />
}
函数FacilsList(){
const[facils,fetchFacils]=useDbFacils();
//后来
{facils.length>0?facils.map。。。
//及
setShowEdit(假)}
handleChange={handleChange}
refreshData={fetchFacils}
/>
}

使用
use
前缀并不是编译的强制要求。它只是帮助react添加验证并为错误使用提供警告:检查此codesandbox:。如果没有前缀react,react将无法验证钩子的规则,但如果正确使用它,它仍然可以工作:感谢您的有用建议..我不知道帽子!我还有一个问题,为什么我不能直接在参数中使用useEffect…?为什么我会得到无限重渲染器…?为什么我应该使用带有返回函数的钩子。我不太清楚…这是我迄今为止读到的最好的一个问题:但是为了回答你的问题,当然你可以这样做。你刚刚发布了一个代码片段,其中有一个c我们为您提供了钩子抓取工具,但您可以将其内容复制到您的组件(将变得巨大)谢谢您的回复!我尝试了您的方法,但我无法使用fetchData()在refreshData中..我得到了未定义的消息变量。并且facils.map不起作用,即使我在数据库中得到了数据,我也看不到任何ul。您在哪里看到错误?您是否已对useGetData进行了解构并正确返回值。另外,为什么不能在refreshData中使用fetchData?在refreshData={()=>fetchData()}…是的,我解构并正确返回值,但我不能使用fetchData变量..如果我在Facility组件和Facility组件外部声明useGetData,我会遇到相同的情况。Oopss..对不起,我没有解构useGetDB挂钩,我会再试一次!我认为这不是“使用” problem@youngbanas你可以在另一个答案中看到,这实际上是不使用的问题。