Reactjs 单击复选框时响应更新获取

Reactjs 单击复选框时响应更新获取,reactjs,checkbox,react-hooks,fetch-api,Reactjs,Checkbox,React Hooks,Fetch Api,我有一个组件(卡),它有一些复选框,这些复选框在本地主机数据库中使用Postgres进行跟踪。当我选中或取消选中该框时,一个条目会被放入networkusers表中。问题是,当我选中或取消选中复选框,然后单击按钮渲染不同的组件,然后返回带有复选框的卡片组件时,这些框不会显示更新的复选框。但是,如果我注销并重新登录,所有框都会更新并与数据库同步。那么,如何让组件在以下组件中的复选框更改后立即进行渲染(或再次获取?)?泰 import React, { useState } from "react"

我有一个组件(卡),它有一些复选框,这些复选框在本地主机数据库中使用Postgres进行跟踪。当我选中或取消选中该框时,一个条目会被放入networkusers表中。问题是,当我选中或取消选中复选框,然后单击按钮渲染不同的组件,然后返回带有复选框的卡片组件时,这些框不会显示更新的复选框。但是,如果我注销并重新登录,所有框都会更新并与数据库同步。那么,如何让组件在以下组件中的复选框更改后立即进行渲染(或再次获取?)?泰

import React, { useState } from "react";

const onUpdateCB = (ischecked, loginuser, userid, setisChecked,handleCheck,event) => {

  console.log(ischecked, loginuser, userid);

  fetch('http://localhost:3000/cb', {
      method: 'post',
      headers: {'Content-Type':'application/json'},
      body:JSON.stringify({
      loginuser,
      userid,
      ischecked: ischecked
    })
  }).then(setisChecked(ischecked)); 
};

const Card = props => {
  const [isChecked, setisChecked] = useState(props.ischecked);
  return (
    <div
      className="pointer bg-light-green dib br3 pa3 ma2 shadow-5"
      onClick={() => props.handleClick(props.id)}
      //onClick={(e) => e.stopPropagation()}

    >
      <div>
        <h3>{props.name}</h3>
        <p>{props.company}</p>
        <p>{props.phone}</p>
        <p>{props.email}</p>
        <p>{props.city}</p>
      </div>
      <div>
        My Network
        <input
          className="largeCheckbox"
          type="checkbox"
          checked={isChecked}
          onClick={(event) =>
            onUpdateCB(!isChecked, props.loginuser.id, props.id, setisChecked,event.stopPropagation())
          }
        />
      </div>
    </div>
  );
};

export default Card;
import React,{useState}来自“React”;
const onUpdateCB=(已检查、登录用户、用户ID、已检查、handleCheck、事件)=>{
log(ischecked、logiuser、userid);
取('http://localhost:3000/cb', {
方法:“post”,
标题:{'Content-Type':'application/json'},
正文:JSON.stringify({
登录用户,
用户ID,
ischecked:ischecked
})
}).然后(设置检查(设置检查));
};
康斯特卡=道具=>{
const[isChecked,setisChecked]=useState(props.isChecked);
返回(
props.handleClick(props.id)}
//onClick={(e)=>e.stopPropagation()}
>
{props.name}
{props.company}

{props.phone}

{props.email}

{props.city}

我的网络 onUpdateCB(!isChecked,props.logiuser.id,props.id,setisChecked,event.stopPropagation()) } /> ); }; 导出默认卡;
网络阵列

import React from "react";
import Card from "./Card";

const NetworkArray = ({
  network,
  networkusers,
  handleChange,
  handleClick,
  loginuser
}) => {
  console.log("in network array", networkusers);

  const cardComponent = network.map((user, i) => {
    const ischecked = networkusers.filter(n => {
      var nw = n.id === loginuser.id && n.connections === network[i].id;
      return nw;
    });



    console.log("i'm checked", ischecked);

    return (

      <Card
        key={network[i].id}
        name={network[i].firstname + " " + network[i].lastname}
        company={network[i].company}
        phone={network[i].phone}
        email={network[i].email}
        city={network[i].city}
        ischecked={ischecked.length}
        handleChange={handleChange}
        handleClick={handleClick}
        id={network[i].id}
        loginuser={loginuser}
      />
    );
  });
  return <div>{cardComponent}</div>;
};

export default NetworkArray;
从“React”导入React;
从“/Card”导入卡片;
常量网络数组=({
网络,,
网络用户,
handleChange,
handleClick,
登录用户
}) => {
console.log(“在网络阵列中”,networkusers);
const cardComponent=network.map((用户,i)=>{
const ischecked=networkusers.filter(n=>{
var nw=n.id==logiuser.id&&n.connections===network[i].id;
返回西北方向;
});
log(“我已检查”,已检查);
返回(
);
});
返回{cardComponent};
};
导出默认网络数组;

我相信,问题出在
卡的家长身上。它传递检查状态的初始值(
props.ischecked
),因此您可能需要通知它状态更改,并使您的
卡在没有自身状态的情况下完全受控

根据您使用的状态管理策略,有几种方法可供选择

  • 如果仅在某个父组件中保持此状态:
  • const Parent=()=>{
    const[ischecked,setChecked]=使用状态(false);
    返回(
    );
    }
    
    在这种情况下,提供回调以将状态更改为
    组件:

    const Parent=()=>{
    ...
    返回(
    );
    }
    ...
    康斯特卡=(道具)=>{
    ...
    返回(
    ...
    onUpdateCB(!isChecked,props.logiuser.id,props.id,props.onCheckedChange,event.stopPropagation())
    }
    />
    );
    }
    
  • 如果使用Redux管理状态-将复选框状态移动到Redux:
  • 从“/actions”导入{setChecked};
    康斯特卡=道具=>{
    //同上
    }
    导出默认连接(状态=>({
    ischecked:state.ischecked
    }), {
    onCheckedChange:setChecked
    })(卡);
    
    另外,您的
    onUpdateCB()
    方法中有一个输入错误-您应该使用一个函数作为承诺回调:

    然后( ()=>setisChecked(ischecked) );

    目前,您只需同时设置选中状态。

    首先,在React应用程序中必须遵循两个原则

    1。不要在任何应用程序状态下存储两个真实来源。 此时,卡存储其自己的状态
    isChecked
    ,并且
    网络上的某个位置
    从数据库中获取值,并将
    isChecked
    传递给卡组件

    拥有多个真理来源是不好的,而且通常会在以后再来困扰我们,所以第一条规则,不要拥有多个真理来源

    Fix#1:从卡中删除“isChecked”状态。

    import React, { useState } from "react";
    
    const onUpdateCB = (ischecked, loginuser, userid) => {
    
      console.log(ischecked, loginuser, userid);
    
      fetch('http://localhost:3000/cb', {
        method: 'post',
        headers: {'Content-Type':'application/json'},
        body:JSON.stringify({
          loginuser,
          userid,
          ischecked: ischecked
        })
      }); 
    };
    
    const Card = props => {
      const { ischecked } = props;
      return (
        <div
          className="pointer bg-light-green dib br3 pa3 ma2 shadow-5"
          onClick={() => props.handleClick(props.id)}
          //onClick={(e) => e.stopPropagation()}
        >
          <div>
            <h3>{props.name}</h3>
            <p>{props.company}</p>
            <p>{props.phone}</p>
            <p>{props.email}</p>
            <p>{props.city}</p>
          </div>
          <div>
            My Network
            <input
              className="largeCheckbox"
              type="checkbox"
              checked={ischecked}
              onClick={(event) =>
                onUpdateCB(!isChecked, props.loginuser.id, props.id)
              }
            />
          </div>
        </div>
      );
    };
    
    export default Card;
    

    让我仔细澄清一下

    第一次渲染

  • 名为ischecked of Card的属性由父组件NetworkArray提供。让我们假设当时它是假的
  • 在子组件卡中,它初始化了一个名为isChecked的本地状态,该状态的初始值与prop isChecked(false)相同,并封装了一些逻辑,以通过用户操作和API响应更新状态。在一系列用户操作之后,假设它最终被更改为true。在代码中,只有本地状态更新,但父级中的道具保持不变
  • 第二次渲染。 然后第二次渲染同一张卡时,属性ischecked再次为false,在该卡中,由于计算的局部状态ischecked为false,因此未选中该属性

    因此,我们看到了卡没有显示更新的isChecked的原因,因为道具isChecked没有更改

    解决此问题的方法是确保对属性进行检查并成功更新,而不仅仅是本地状态。我不知道如何在您的代码中实现这一点,因为已检查是由许多其他道具计算出来的,请尝试自己实现,祝您好运


    最后,为什么在注销和登录后没有出现此问题?因为通过这种方式,父级中的道具完全重新加载了更新的数据,包括ischecked相关片段。所以您得到了复选框的更新值。就是这样。

    在React中,当一个组件卸载时,它会释放其内部状态

    因此,当您返回时,您必须确保从车上检查
    道具
    
    const onUpdateCB = (ischecked, loginuser, userid) => {
      return fetch('http://localhost:3000/cb', {
        method: 'post',
        headers: {'Content-Type':'application/json'},
        body:JSON.stringify({
          loginuser,
          userid,
          ischecked: ischecked
        })
      }); 
    }
    
    const Card = props => {
      const [data, setData] = useState({});
    
      // 2: set new state
      const onSelectCheckbox = (ischecked) => {
        const newData = { ...data, ischecked };
        setData(newData);
      }
    
      useEffect(() => {
        // 4. Watch if data.ischecked change, if yes perform side effect (call api)
        onUpdateCB(data.ischecked, props.loginuser.id, props.id);
      }, [data.ischecked]);
    
      // 3. re-render when data change.
      const { name, company, phone, email, city, ischecked } = data;
      return (
        <div className="pointer bg-light-green dib br3 pa3 ma2 shadow-5">
          <div>
            <h3>{name}</h3>
            <p>{company}</p>
            <p>{phone}</p>
            <p>{email}</p>
            <p>{city}</p>
          </div>
          <div>
            My Network
            <input
              className="largeCheckbox"
              type="checkbox"
              checked={ischecked}
              onClick={(event) =>
                onSelectCheckbox(!isChecked) // 1. User interact with checkbox
              }
            />
          </div>
        </div>
      );
    };