【发布时间】:2021-10-27 01:05:24
【问题描述】:
我正在尝试在侧边栏组件中处理在上下文值更改时重新渲染表格组件 (currentRep),我正在使用useContext。 When the selection is changed, the state at the App-level changes, which is passed through the context provider.此上下文在表组件中使用并触发useEffect 挂钩以获取数据。虽然触发了这个钩子,但表格不会重新渲染。我在某处读到 useContext 钩子每次都会触发值变化的渲染,所以我对(缺乏)结果感到困惑。
我可以确认,在选择更改时,表中的useEffect 挂钩会触发,并且我会收到 API 响应。 我缺少什么导致重新渲染?我尝试将setCurrentRep 设置为App 级别的状态设置器,但这并没有改变任何东西。
这是创建的上下文:
Context.tsx
import React from 'react'
import { AccountRep } from './Data';
export interface InfoContextInterface {
repData:AccountRep[];
currentRep: string;
setCurrentRep: (r:string) => void;
}
const InfoContext = React.createContext<InfoContextInterface>({
repData: [],
currentRep:"",
setCurrentRep: (rep) => {}
});
export const InfoProvider = InfoContext.Provider
export default InfoContext
上下文提供者是App-level 中的父级:
App.tsx
import React, {useState, useRef, useEffect} from 'react'
import Sidebar from './Sidebar'
import {Switch,Route,useLocation} from 'react-router-dom';
import Home from './pages/Home'
import SchoolInfo from './pages/SchoolInfo'
import {InfoProvider} from './Context'
import {Location} from 'history'
import {AccountRep} from './Data'
export default function App() {
const [data, setData] = useState<AccountRep[]>([]);
const [currentRep,setCurrentRep] = useState("")
const cancelRequest = useRef<boolean>(false);
let location = useLocation()
let locState = location.state as locationStateProps
let background = locState && locState.background
useEffect(() => {
const getReps = async () => {
const req = await (await fetch(`http://localhost:8080/api/reps`)).json()
if (cancelRequest.current) {return}
setData(req)
};
void getReps()
return () => {
cancelRequest.current = true
}
}, []);
return (
<>
<InfoProvider value={{repData:data,currentRep:currentRep,setCurrentRep}}>
<Sidebar />
<Switch location={background || location}>
<Route exact path='/' children={<Home/>}/>
<Route path='/school-info' exact children={<SchoolInfo />}/>
</Switch>
</InfoProvider>
</>
);
};
带有选择的侧边栏,其中上下文发生变化:
Sidebar.tsx
import React, {useState, useCallback,useContext} from 'react'
import './Sidebar.css'
import InfoContext from './Context'
import {AccountRep} from './Data'
const RepViewDropdown = () => {
const [selectState, setState] = useState("");
const context = useContext(InfoContext)
const handleChangeHandler = useCallback((event: React.FormEvent<HTMLSelectElement>): void => {
setState(event.currentTarget.value)
context.setCurrentRep(event.currentTarget.value)
},[]);
const renderOptions = (repData: AccountRep[]) => {
return repData.map(obj => {
return <option key={obj.id} value={obj.id}>{obj.first_name}</option>
})
}
return (
<fieldset>
<legend>Account Rep</legend>
<select value={selectState} id="select-rep" onChange={handleChangeHandler}>
<option value="">All</option>
{renderOptions(context.repData)}
</select>
</fieldset>
)
}
const Sidebar = () => {
return (
<div className="sidebar">
<RepViewDropdown />
</div>
)
}
export default Sidebar;
以及相关的表格组件:
Table.tsx
import { useEffect, useState, useRef, useContext } from 'react';
import { Link, useLocation } from 'react-router-dom';
import InfoContext,{ InfoContextInterface } from '../Context'
import { School } from '../Data'
import CreateSchoolModal from '../CreateSchoolModal';
import './SchoolInfo.css'
interface SchoolInfoTableRowProps {
data: School;
}
const SchoolInfoTableRow = (props:SchoolInfoTableRowProps) => {
const location = useLocation()
return (
<tr>
<td><Link to={{
pathname:`/school/${props.data.id}`,
state: { background: location }
}}>{props.data.name}</Link></td>
<td><Link to={{
pathname:`/school/${props.data.id}`,
state: { background: location }
}}>{props.data.code}</Link></td>
<td><Link to={{
pathname:`/school/${props.data.id}`,
state: { background: location }
}}>{props.data.address}</Link></td>
</tr>
)
}
const SchoolInfoTable = () => {
const cancelRequest = useRef<boolean>(false);
const [data, setData] = useState<School[]>([]);
const context: InfoContextInterface = useContext(InfoContext)
useEffect(() => {
const fetchData = async () => {
const res = await (await fetch(`http://localhost:8080/api/schools${context.currentRep !== "" ? `?account_rep_id=${context.currentRep}` : ""}`)).json()
if (cancelRequest.current) { return }
setData(res)
};
void fetchData();
console.log(context.currentRep)
return () => {
cancelRequest.current = true
}
}, [context.currentRep]);
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Code</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{data.map((obj,i) => {
return ( <SchoolInfoTableRow key={i} data={obj}/> )
})}
</tbody>
</table>
)
}
const SchoolInfo = () => {
const [showModal, setModal] = useState(false)
const openModal = () => {
setModal(prev => !prev)
}
return (
<div id='school-info'>
<h1 className='page-header'>School Info</h1>
<div className="table-buttonset">
<div className="buttonset">
<button onClick={openModal}>Add School</button>
<button disabled>Test Button</button>
<button disabled>Test Button</button>
</div>
<SchoolInfoTable/>
<CreateSchoolModal showModal={showModal} setModal={setModal}/>
</div>
</div>
)
}
export default SchoolInfo;
【问题讨论】:
标签: reactjs react-hooks