reactjs 如何在原有增删改基础添加检索功能?

66 阅读2分钟

问题:初次接触reactJS,面对这个课题以为很简单,不巧出了这么大的错误?

    useEffect(()=>{
    
       let ret = useSwrResult(`/api/companies/${companyId}/users`, companyUserListFetcher, true);

       if(!ret.isLoading){
           setUsers(ret.data);
       }

    // },[searchItem]);

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app See reactjs.org/link/invali… for tips about how to debug and fix this problem.

如何解决问题:经过函数调用,中间组件调用后都出同样的错误;学习react后,试着把功能再拆分

原先的组件结构:

  • Page组件
  • Row组件
  • RowClass组件
  • 追加画面组件/更新画面组件

重构的组件结构

  • Page组件
  • SearchBar组件
  • ItemList组件
  • RowClass组件
  • 追加画面组件/更新画面组件

由SearchBar产生检索条件,ItemList根据检索条件实时搜索数据

关键点使用useEffect及api调用在初始化时,下面看代码结构:

SearchBar.tsx

interface SearchBarProps {
    setSearchItem: Dispatch<SetStateAction<string>>;
}
export const SearchBar = ({setSearchItem}: SearchBarProps)=> {
    const [name, nameChanged,,,reset] = useInput("");
    const handleSearch =()=>{
        setSearchItem(name);
    }
    const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
        if (e.nativeEvent.isComposing || e.key !== 'Enter') return
        handleSearch();
    }
    const handleReset = () => {
        reset();
    };
    
 };
 
 return (<>
           <Input
               type="text"
               size={55}
               onChange={nameChanged}
               onKeyDown={handleKeyDown} 
               value={name}
           />
            <Clear type="button" onClick={handleReset}>
                清除
            </Clear>
            <Search
            type="button"
            onClick={handleSearch}
            >
                检索
            </Search>
 </>);

SearchUserList.tsx

interface SearchUserListProps {
    cond: string | "";
    companyId: number;
}
export const SearchUserList = ({cond, companyId}:SearchUserListProps)=>{
    const {data: users, isLoading: isLoadingUsers} = useCompanyUserListByCond(companyId, cond);
    const [sortConfig, setSortConfig] = useState(null);

    const [stateUsers,setUsers] = useState([]);

    const renewUsers = (users)=>{
          users.map(user => {
              const getUserStatus =()=>{

                  return  {label:"",sort:"D"};;
              };
              const getUserRole =()=>{
                  return  {label:"",sort:"F"};;
              };
              user.status = getUserStatus();
              user.role = getUserRole();
        });
    }
    useEffect(()=>{
        if(users != undefined){
            setSortConfig({key:'',direction:''});
            renewUsers(users);
            users.sort(statusAndFirstLastNameComparator);
            setUsers(users);
        }

    },[users]);

    if(isLoadingUsers){
        return (
            <LoadingMessage fadeInAfterMs={1000}>
                Loading users...
            </LoadingMessage>
        );
    }else{

        return(
            <>
                <SortHeader users={users} setUsers={setUsers} renewUsers={renewUsers} sortConfig={sortConfig} setSortConfig={setSortConfig}/>
                {stateUsers.map(user => (
                    <UserCard key={user.id} user={user} cond={cond} />
                ))}
            </>
        );
    }

};

SortHeader.tsx

export const SortHeader = ({users,setUsers,renewUsers,sortConfig,setSortConfig}: SortHeaderProps) => {
  
  useEffect(()=> {
    renewUsers(users);
    let sortableItems = [...users];
    if (sortConfig !== null) {
      sortableItems.sort((a, b) => {
        let keyArray = sortConfig.key.split('.');
        if(keyArray.length > 1){
            if (a[keyArray[0]].sort < b[keyArray[0]].sort) {
              return sortConfig.direction === 'ascending' ? -1 : 1;
            }
            if (a[keyArray[0]].sort > b[keyArray[0]].sort) {
              return sortConfig.direction === 'descending' ? -1 : 1;
            }
            return 0;
        }else{
            if (a[sortConfig.key] < b[sortConfig.key]) {
              return sortConfig.direction === 'ascending' ? -1 : 1;
            }
            if (a[sortConfig.key] > b[sortConfig.key]) {
              return sortConfig.direction === 'descending' ? -1 : 1;
            }
            return 0;
        }
      });
    }
    setUsers(sortableItems)
  }, [sortConfig]);

  const requestSort = (key) => {
    let direction = 'ascending';
    if (
      sortConfig &&
      sortConfig.key === key &&
      sortConfig.direction === 'ascending'
    ) {
      direction = 'descending';
    }
    setSortConfig(() => {return { key, direction }});
  };

  const handleClick=(key)=>{
    requestSort(key);
  }

  const getClassNamesFor = (name) => {
    if (!sortConfig) {
      return undefined;
    }
    if(sortConfig.key === name){
      if(sortConfig.direction == 'ascending'){
        return <AscendingIcon size={15} color="greenLight"/>
      }else if(sortConfig.direction == 'descending'){
        return <DescendingIcon size={15} color="greenLight"/>
      }else{
        return undefined;;
      }
    }else{
      return undefined;;
    }
  };
  return (
    <LockWidth>
      <Row align="center">
        <BlankCell/>
        <ColumnCell width={190}>
          <UnstyledButton onClick={() => handleClick('name')} >名称{getClassNamesFor('name')}</UnstyledButton>
        </ColumnCell>
      </Row>
    </LockWidth>
  );
};

UserCard.tsx

interface UserCardProps {
    user: User;
    cond: string;
}

export const UserCard = ({user,cond}: UserCardProps) => {

    return (
        <>
        </>
    );
};

追记: react框架的特性,经常会用到useState,引发问题如下:

场景:

当画面分上下两部分,上部分不需要刷新,下部分实时刷新。

问题:

如何下部分的变量变更,反映到上部分(而又不须刷新上部分画面)?为此困扰半日,下半部分钟的分页号总是不能反映到检索API

解决:

原因:useState只有在刷新页面才能使用新值 可以借用useEffect来监控变量的最新变化,从而实现棘手的问题。

  useEffect(()=>{
    if (ids.length === 0) {
      return;
    }
    if(isSearch){
      const param: TestParamType = {,
        page: page,
        limit: limit,
      };
      getData(param)
    }
  },[page,limit]);