如何解决当原子状态更新为先前值时,React Recoil选择器不会触发其获取
我已经通过做一个自己的快速项目开始学习React和Recoil。一个具有按钮的单页网站,简而言之,每个按钮都会进行REST调用,并创建一个带有返回数据的表。
单击按钮时,它将更新一个原子,该原子存储给定按钮的URL。选择器已订阅该原子,并触发对API的异步REST请求。从那里,返回的数据被处理到一个表中。
在每个按钮的第一次单击上,所有操作均按预期进行。调用特定的URL并生成表。问题是,如果第二次单击按钮,则会显示先前获取的数据。我不确定是否缺少重要的步骤,并且调试并没有真正向我透露任何内容。
原子类:
import {atom} from 'recoil'
export const currentTableState = atom({
key: 'currentTableState',default: 'Employee',})
export const currentUrlState = atom({
key: 'currentUrlState',default: '/employee/find/all?page=0&size=12'
})
export const currentPageState = atom({
key: 'currentPageState',default: 0
})
export const currentSizeState = atom({
key: 'currentSizeState',default: 12
})
选择器类:
import {selector} from "recoil";
import {currentUrlState} from "./atoms";
export const tableData = selector({
key: "currentContactDetails",get: async ({get}) => {
const response = await fetch(String(get(currentUrlState)));
const json = await response.json();
return json.content;
}
});
包含按钮的NavBar类:
import React from "react";
import './topNavBar.css';
import {useSetRecoilState,useRecoilValue} from "recoil";
import {currentPageState,currentSizeState,currentTableState,currentUrlState} from "../recoil/atoms";
const TopNavBar = () => {
const setCurrentTable = useSetRecoilState(currentTableState);
const setUrl = useSetRecoilState(currentUrlState);
const page = useRecoilValue(currentPageState);
const size = useRecoilValue(currentSizeState);
function updateState(table) {
setCurrentTable(table);
if (table.includes(" ")) {
let split = table.split(" ");
table = split[1] + '/' + split[0];
}
setUrl(`${table.toLowerCase()}/find/all?page=${page}&size=${size}`);
}
return (
<div className='top-nav'>
<button onClick={() => updateState("Employee")}>Employee
</button>
<button onClick={() => updateState("Material")}>Material
</button>
<button onClick={() => updateState("Equipment")}>Equipment
</button>
<button onClick={() => updateState("Material Request")}>Material Request
</button>
<button onClick={() => updateState("Equipment Request")}>Equipment Request
</button>
</div>
)
}
export default TopNavBar;
生成表的表类:
import React from "react";
import './table.css'
import {useRecoilState,useRecoilValueLoadable} from "recoil";
import {currentTableState} from "../recoil/atoms";
import {tableData} from "../recoil/selectors";
const Table = () => {
const [currentTable] = useRecoilState(currentTableState);
const items = useRecoilValueLoadable(tableData);
const Data = () => {
switch (items.state) {
case 'loading':
return <div>Loading...</div>;
case 'hasError':
throw items.contents;
case 'hasValue':
return <ConstructTable items={items.contents}/>
default:
return <div>Something went terribly wrong.</div>
}
}
const TableHeaders = (headers) => <tr>{headers.headers.map(key => <th key={key.toString()}>{key}</th>)}</tr>;
const TableRows = (items) =>
items.items.map(row =>
<tr className='body' key={row.id}>
{Object.values(row).map((cell,cellIndex) => <td key={cellIndex}>{cell}</td>)}
</tr>
)
const ConstructTable = (content) => {
let {items} = content
if (items.length === 0) return <div>{currentTable} table has no data...</div>
else return (
<div className="table">
<table>
<thead>
<tr>
<th
className="table-name"
colSpan={Object.keys(items[0]).length}
>
{currentTable}
</th>
</tr>
<TableHeaders headers={Object.keys(items[0])}/>
</thead>
<tbody>
<TableRows items={items}/>
</tbody>
</table>
</div>
);
}
return <Data/>
}
export default Table;
更新: 通过放弃使用选择器以及混合使用钩子和原子来获得类似的功能,我解决了这个问题,例如:
const url = useRecoilValue(currentUrlState);
const table = useRecoilValue(currentTableState);
const [data,setData] = useRecoilState(currentTableData);
const [requestState,setRequestState] = useState('loading');
useEffect(() => {
console.debug('use effect triggered')
setRequestState('loading');
fetch(String(url))
.then(res => res.json())
.then(
(result) => {
setData(result.content);
setRequestState('loaded');
},(error) => setRequestState(error.message)
);
},[url,setData])
const Data = () => {
switch (requestState) {
case 'loading':
return <div>Loading...</div>;
case 'loaded':
return <ConstructTable items={data}/>
default:
return <div>{requestState}</div>
}
}
尽管我不认为这是理想的。
解决方法
好吧,我根据您的第一个版本创建了一个沙箱。它似乎工作正常。 注意:仅启用员工和物料按钮。表格数据也与您的不同。但它应该说明这个想法。
https://codesandbox.io/s/friendly-wiles-kjpjw?file=/src/Table.js
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。